WCF Self-Host to access from internet - c#

I am trying to create a service to consume it through the internet, but for some reason I cannot access it and I need help finding the error I am making.
I leave the code for you to see.
public class ServiceHost<T> : System.ServiceModel.ServiceHost
{
public ServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
public ServiceHost(object singletonInstance, params Uri[] baseAddresses)
:base(singletonInstance, baseAddresses)
{
}
protected ServiceHost()
: base()
{
}
public void EnableMetadataExchange(bool enableHttpGet = true)
{
if (State == CommunicationState.Opened)
{
throw new InvalidOperationException("La comunicación ya está abierta");
}
ServiceMetadataBehavior metadataBehavior
= Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
Description.Behaviors.Add(metadataBehavior);
if (BaseAddresses.Any(uri => uri.Scheme == "http"))
metadataBehavior.HttpGetEnabled = enableHttpGet;
}
AddAllMexEndPoints();
}
public bool HasMexEndpoint
{
get
{
return Description.Endpoints.Any(
endpoint => endpoint.Contract.ContractType ==
typeof(IMetadataExchange));
}
}
private void AddAllMexEndPoints()
{
Debug.Assert(HasMexEndpoint == false);
foreach (Uri baseAddress in BaseAddresses)
{
Binding binding = null;
switch (baseAddress.Scheme)
{
case "net.tcp":
{
binding = MetadataExchangeBindings.CreateMexTcpBinding();
break;
}
case "http":
{
binding = MetadataExchangeBindings.CreateMexHttpBinding();
break;
}
case "https":
{
binding = MetadataExchangeBindings.CreateMexHttpsBinding();
break;
}
case "net.pipe":
{
binding = MetadataExchangeBindings.CreateMexNamedPipeBinding();
break;
}
}
if (binding != null)
{
AddServiceEndpoint(typeof(IMetadataExchange), binding, "MEX");
}
}
}
}
Hosting
public void HostService()
{
try
{
Uri tcpBaseAddress = new Uri("net.tcp://192.168.1.110:28620/");
Uri httpBaseAddress = new Uri("http://192.168.1.110:28621/");
ServiceHost<wesling.Services.GC> host = new ServiceHost<wesling.Services.GC>(typeof(wesling.Services.GC), tcpBaseAddress, httpBaseAddress);
//add tcp binding
var netTcpBinding = new NetTcpBinding()
{
MaxBufferPoolSize = int.MaxValue,
MaxReceivedMessageSize = int.MaxValue,
ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxStringContentLength = int.MaxValue
},
};
netTcpBinding.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(wesling.Services.IGC), netTcpBinding, "GC");
//add WSHttp binding
var httpBinding = new WSHttpBinding()
{
MaxBufferPoolSize = int.MaxValue,
MaxReceivedMessageSize = int.MaxValue,
ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxStringContentLength = int.MaxValue
},
};
httpBinding.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(wesling.Services.IGC), httpBinding, "GC");
host.EnableMetadataExchange(true);
host.Open();
}
catch (CommunicationException ce)
{
MessageBox.Show(ce.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The uri ip is the lan ip of the pc where the service is hosted
The customer is like this
public async void GetProduct()
{
try
{
var endPointConfiguration = "WSHttpBinding_IGC";//cfg.GetEndPointConfiguration();
var address = "http://fabianwesling.dynu.com:28621/GC"; //cfg.getAddress();
ServiceReference1.GCClient service = new ServiceReference1.GCClient(endPointConfiguration, address);
var bindins = service.Endpoint.Binding;
if (bindins is NetTcpBinding tcpBinding)
{
tcpBinding.MaxBufferPoolSize = int.MaxValue;
tcpBinding.MaxReceivedMessageSize = int.MaxValue;
tcpBinding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
}
else if (bindins is WSHttpBinding wS)
{
wS.MaxBufferPoolSize = int.MaxValue;
wS.MaxReceivedMessageSize = int.MaxValue;
wS.ReaderQuotas.MaxStringContentLength = int.MaxValue;
}
var result = await service.GetProductsAsync();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I opened the ports in the Reuter so that it directs those ports to the pc, and I also opened the ports in the firewall, I also activated the Windows .net framework features. But when I try to connect from the client, it tells me that there was no end listening
There must be some concept that I am not understanding, but I cannot identify what it is ... I need your advice, everything is welcome

First try to use the browser on the client computer to visit http//fabianwesling.dynu.com:28621/GC to see if the metadata can be accessed normally.If not, the client and server cannot access normally. Modify the hots file on the client computer:
All in all, you must ensure that the client and server are mutually accessible on the Internet.
If it is not a network problem, you can create a simple WCF service for testing to know where the problem is.Here is a very simple example of WCF service:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/getting-started-tutorial
UPDATE
This is my remote WCF service:
Baseadress is the WAN IP.
Ensure that the local computer can access the WSDL of the remote service through a browser

Related

Wcf auto-host que permite conexiones a través de Internet

I need to create a self-hosted WCF service, which allows access through the internet, and it throws this error at me ”System.ServiceModel.EndpointNotFoundException: There was no end listening on http://fabianwesling.dynu.com:28620/HostManager/Service that could accept the message. The cause is usually an incorrect SOAP address or action. ”
can someone help me what is the mistake I am making, I have opened the ports on the router, router firewall and Windows and deactivate the antivirus
… I show you what I have done.
Service
[ServiceContract()]
public interface IService
{
[OperationContract()]
int SumValues(int value1, int value2);
}
public class Service : IService
{
public static void Configure(ServiceConfiguration config)
{
config.Description.Behaviors.Add(new ServiceMetadataBehavior
{
HttpGetEnabled = true
});
config.Description.Behaviors.Add(new ServiceDebugBehavior
{
IncludeExceptionDetailInFaults = true,
});
config.EnableProtocol(new BasicHttpBinding() );
config.EnableProtocol(new NetTcpBinding());
}
public int SumValues(int value1, int value2)
{
return value1 + value2;
}
}
Run server local Host
Uri http_Uri = new Uri("http://192.168.1.100:28620/HostManager/Service");
Uri netTCP_Uri = new Uri("net.tcp://192.168.1.100:28621/HostManager/Service");
host = new ServiceHost(typeof(HostManager.Services.Service), http_Uri,netTCP_Uri );
host.Open();
Run server to access from internet
Uri http_Uri = new Uri("http://fabianwesling.dynu.com:28620/HostManager/Service");
Uri netTCP_Uri = new Uri("net.tcp://fabianwesling.dynu.com:28621/HostManager/Service");
host = new ServiceHost(typeof(HostManager.Services.Service), http_Uri);
host.Open();
client local connection
EndpointAddress uri = new EndpointAddress("http://192.168.1.100:28620/HostManager/Service");
ServiceReference1.ServiceClient service = new ServiceReference1.ServiceClient("BasicHttpBinding_IService", uri);//http binding
//EndpointAddress uri = new EndpointAddress("net.tcp://192.168.1.100:28621/HostManager/Service");
//ServiceReference1.ServiceClient service = new ServiceReference1.ServiceClient("NetTcpBinding_IService", uri); ///net-tcp binding
var result = service.SumValues(GetNumber(), GetNumber());
client connection through internet
//http binding
EndpointAddress uri = new EndpointAddress(" http://fabianwesling.dynu.com/:28620/HostManager/Service");
ServiceReference1.ServiceClient service = new ServiceReference1.ServiceClient("BasicHttpBinding_IService", uri);
//net-tcp binding
//EndpointAddress uri = new EndpointAddress(" http://fabianwesling.dynu.com/:28620/HostManager/Service");
//ServiceReference1.ServiceClient service = new ServiceReference1.ServiceClient("NetTcpBinding_IService", uri);
var result = service.SumValues(GetNumber(), GetNumber());
Modify domain name to IP address:
EndpointAddress uri = new EndpointAddress(" http://xxx.xxx.xxx.xxx/:28620/HostManager/Service");
ServiceReference1.ServiceClient service = new ServiceReference1.ServiceClient("BasicHttpBinding_IService", uri);
var result = service.SumValues(GetNumber(), GetNumber());
Ensure that the IP address is an IP address on the public network.

UdpClient wont connect to IpAdress.Any

I'm trying to listen for UDP packets from unknown source. But can't bind on the "unspecified adress" (0.0.0.0 or ::)
I've already tried listening on ::1. But from what i tested that only works for local connections that don't pass the network interface.
public async void AwaitDiscoveryReply()
{
try
{
using (var client = new UdpClient(AddressFamily.InterNetworkV6))
{
client.Connect(IPAddress.IPv6Any,4568);
var result = await client.ReceiveAsync();
Debug.WriteLine("Received DR");
var stateProtocol = StateProtocol.FromBytes(result.Buffer);
var robeatsDevice = new RobeatsDevice
{
Id = stateProtocol.DeviceId,
Name = stateProtocol.DeviceName,
EndPoint = client.Client.RemoteEndPoint,
StateProtocol = stateProtocol
};
OnDiscoveryReply(new DeviceDiscoveryEventArgs {RobeatsDevice = robeatsDevice});
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
This keeps throwing the exception: The requested address is not valid in its context [::]:4568
UDP sockets are connectionless. "Connect" methods on UDP socket implementations, by convention (don't ask me why) establish default endpoints / filter traffic. If you want to receive traffic from any address, you don't need to "connect" at all. Use the constructor with signature UdpClient(Int32, AddressFamily) and delete the Connect() invocation:
public async void AwaitDiscoveryReply()
{
try
{
using (var client = new UdpClient(4568,AddressFamily.InterNetworkV6))
{
var result = await client.ReceiveAsync();
Debug.WriteLine("Received DR");
var stateProtocol = StateProtocol.FromBytes(result.Buffer);
var robeatsDevice = new RobeatsDevice
{
Id = stateProtocol.DeviceId,
Name = stateProtocol.DeviceName,
EndPoint = client.Client.RemoteEndPoint,
StateProtocol = stateProtocol
};
OnDiscoveryReply(new DeviceDiscoveryEventArgs {RobeatsDevice = robeatsDevice});
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}

wsHttpBinding workarounds in .NET Core

I am looking for a dotnet core WCF wsHttpBinding workaround.
I am aware that .net core WCF implementation currently does not support wsHttpBinding (see support matrix here https://github.com/dotnet/wcf/blob/master/release-notes/SupportedFeatures-v2.1.0.md)
I'm integrating with a legacy third party service that appears to only support wsHttpBinding. Our tech stack is .net core, so I cannot revert to the full version of .net framework or mono variant.
The question is whether it's possible to use the service via custom bindings? I am hoping that there is a workaround that maybe isn't fully functional, but at least allows me to consume the service.
var cBinding = new CustomBinding();
var textBindingElement = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.Soap12WSAddressing10
};
cBinding.Elements.Add(textBindingElement);
var httpBindingElement =
new HttpsTransportBindingElement
{
AllowCookies = true, MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue,
};
cBinding.Elements.Add(httpBindingElement);
var myEndpoint = new EndpointAddress("https://..../Service.svc/wss");
using (var myChannelFactory = new ChannelFactory<ISearch>(cBinding, myEndpoint))
{
myChannelFactory.Credentials.UserName.UserName = "...";
myChannelFactory.Credentials.UserName.Password = "...";
ISearch client = null;
try
{
client = myChannelFactory.CreateChannel();
var result = client.Find(new Search("Criteria")).Result;
((ICommunicationObject)client).Close();
myChannelFactory.Close();
}
catch (Exception ex)
{
(client as ICommunicationObject)?.Abort();
}
}
Client gets created and a call is made to the service, but it fails because:
Message = "The message could not be processed. This is most likely because the action '' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between binding
Forget it, they are not completely compatible with Core. Under some specified case, there may be a basic call to WsHttpBinding. You could refer to the following example.
Server.
Uri uri = new Uri("http://localhost:11011");
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
using (ServiceHost sh=new ServiceHost(typeof(MyService),uri))
{
sh.AddServiceEndpoint(typeof(IService), binding, "");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb==null)
{
smb = new ServiceMetadataBehavior()
{
};
sh.Description.Behaviors.Add(smb);
}
Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
sh.Opened += delegate
{
Console.WriteLine("Service is ready");
};
sh.Closed += delegate
{
Console.WriteLine("Service is clsoed");
};
sh.Open();
Client(auto-generated)
private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
{
if ((endpointConfiguration == EndpointConfiguration.WSHttpBinding_IService))
{
System.ServiceModel.Channels.CustomBinding result = new System.ServiceModel.Channels.CustomBinding();
System.ServiceModel.Channels.TextMessageEncodingBindingElement textBindingElement = new System.ServiceModel.Channels.TextMessageEncodingBindingElement();
result.Elements.Add(textBindingElement);
System.ServiceModel.Channels.HttpTransportBindingElement httpBindingElement = new System.ServiceModel.Channels.HttpTransportBindingElement();
httpBindingElement.AllowCookies = true;
httpBindingElement.MaxBufferSize = int.MaxValue;
httpBindingElement.MaxReceivedMessageSize = int.MaxValue;
result.Elements.Add(httpBindingElement);
return result;
}
Invocation.
ServiceReference1.ServiceClient client2 = new ServiceReference1.ServiceClient();
try
{
var res = client2.SayHelloAsync();
Console.WriteLine(res.Result);
}
catch (Exception)
{
throw;
}
While in most cases it is impossible to call WCF service created by WsHttpBinding.
Officials also have no intention of continuing to support plan for wshttpbinding.
Here are related discussions.
https://github.com/dotnet/wcf/issues/31
https://github.com/dotnet/wcf/issues/1370

RabbitMQ durable queue does not work (RPC-Server, RPC-Client)

I wondering why my RabbitMQ RPC-Client always processed the dead messages after restart. _channel.QueueDeclare(queue, false, false, false, null); should disable buffers. If I overload the QueueDeclare inside the RPC-Client I can't connect to the server. Is something wrong here? Any idea how to fix this problem?
RPC-Server
new Thread(() =>
{
var factory = new ConnectionFactory { HostName = _hostname };
if (_port > 0)
factory.Port = _port;
_connection = factory.CreateConnection();
_channel = _connection.CreateModel();
_channel.QueueDeclare(queue, false, false, false, null);
_channel.BasicQos(0, 1, false);
var consumer = new QueueingBasicConsumer(_channel);
_channel.BasicConsume(queue, false, consumer);
IsRunning = true;
while (IsRunning)
{
BasicDeliverEventArgs ea;
try {
ea = consumer.Queue.Dequeue();
}
catch (Exception ex) {
IsRunning = false;
}
var body = ea.Body;
var props = ea.BasicProperties;
var replyProps = _channel.CreateBasicProperties();
replyProps.CorrelationId = props.CorrelationId;
var xmlRequest = Encoding.UTF8.GetString(body);
var messageRequest = XmlSerializer.DeserializeObject(xmlRequest, typeof(Message)) as Message;
var messageResponse = handler(messageRequest);
_channel.BasicPublish("", props.ReplyTo, replyProps,
messageResponse);
_channel.BasicAck(ea.DeliveryTag, false);
}
}).Start();
RPC-Client
public void Start()
{
if (IsRunning)
return;
var factory = new ConnectionFactory {
HostName = _hostname,
Endpoint = _port <= 0 ? new AmqpTcpEndpoint(_endpoint)
: new AmqpTcpEndpoint(_endpoint, _port)
};
_connection = factory.CreateConnection();
_channel = _connection.CreateModel();
_replyQueueName = _channel.QueueDeclare(); // Do not connect any more
_consumer = new QueueingBasicConsumer(_channel);
_channel.BasicConsume(_replyQueueName, true, _consumer);
IsRunning = true;
}
public Message Call(Message message)
{
if (!IsRunning)
throw new Exception("Connection is not open.");
var corrId = Guid.NewGuid().ToString().Replace("-", "");
var props = _channel.CreateBasicProperties();
props.ReplyTo = _replyQueueName;
props.CorrelationId = corrId;
if (!String.IsNullOrEmpty(_application))
props.AppId = _application;
message.InitializeProperties(_hostname, _nodeId, _uniqueId, props);
var messageBytes = Encoding.UTF8.GetBytes(XmlSerializer.ConvertToString(message));
_channel.BasicPublish("", _queue, props, messageBytes);
try
{
while (IsRunning)
{
var ea = _consumer.Queue.Dequeue();
if (ea.BasicProperties.CorrelationId == corrId)
{
var xmlResponse = Encoding.UTF8.GetString(ea.Body);
try
{
return XmlSerializer.DeserializeObject(xmlResponse, typeof(Message)) as Message;
}
catch(Exception ex)
{
IsRunning = false;
return null;
}
}
}
}
catch (EndOfStreamException ex)
{
IsRunning = false;
return null;
}
return null;
}
Try setting the DeliveryMode property to non-persistent (1) in your RPC-Client code like this:
public Message Call(Message message)
{
...
var props = _channel.CreateBasicProperties();
props.DeliveryMode = 1; //you might want to do this in your RPC-Server as well
...
}
AMQP Model Explained contains very useful resources, like explaining how to handle messages that end up in the dead letter queue.
Another useful note from the documentation with regards to queue durability:
Durable queues are persisted to disk and thus survive broker restarts.
Queues that are not durable are called transient. Not all scenarios
and use cases mandate queues to be durable.
Durability of a queue does not make messages that are routed to that
queue durable. If broker is taken down and then brought back up,
durable queue will be re-declared during broker startup, however, only
persistent messages will be recovered.
Note that it talks about broker restart not publisher or consumer restart.

Convert web service configuration to code

I have a client for SOAP service in a console application, I need to move the service client to sharepoint 2010. I do not want to do config files deployment and other sharepoint-related stuff, so I decided to hardcode binding information, the only configurable option is URL. But I encountred some troubles doing this. I have a config:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="SI_PMProjectMaintain_SOUTBinding">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap11" writeEncoding="utf-8">
<readerQuotas maxDepth="10000000" maxStringContentLength="10000000"
maxArrayLength="67108864" maxBytesPerRead="65536" maxNameTableCharCount="100000" />
</textMessageEncoding>
<httpTransport authenticationScheme="Basic" bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard" keepAliveEnabled="false"
proxyAuthenticationScheme="Basic" realm="XISOAPApps" useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://url/XISOAPAdapter/MessageServlet?senderParty=&senderService=Param1&receiverParty=&receiverService=&interface=interface&interfaceNamespace=url"
binding="customBinding" bindingConfiguration="SI_PMProjectMaintain_SOUTBinding"
contract="PmProjectMaintain.SI_PMProjectMaintain_SOUT" name="HTTP_Port" />
</client>
Also, I have a code:
var service = new ServiceClient();
service.ClientCredentials.Windows.ClientCredential = new NetworkCredential("user", "password");
service.ClientCredentials.UserName.UserName = "user";
service.ClientCredentials.UserName.Password = "password";
var resp = service.Operation();
Console.WriteLine(resp.Response);
It works as expected. Now I want to get rid of xml config and completly move it to code:
public class CustomHttpTransportBinding : CustomBinding
{
public CustomHttpTransportBinding()
{
}
public override BindingElementCollection CreateBindingElements()
{
var result = new BindingElementCollection();
result.Add(new TextMessageEncodingBindingElement
{
MaxReadPoolSize = 64,
MaxWritePoolSize = 16,
MessageVersion = MessageVersion.Soap11,
WriteEncoding = Encoding.UTF8,
//ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas
//{
// MaxDepth = 10000000,
// MaxStringContentLength = 10000000,
// MaxArrayLength = 67108864,
// MaxBytesPerRead = 65536,
// MaxNameTableCharCount = 100000
//}
});
result.Add(new HttpTransportBindingElement
{
AuthenticationScheme = AuthenticationSchemes.Basic,
BypassProxyOnLocal = false,
HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.StrongWildcard,
KeepAliveEnabled = false,
ProxyAuthenticationScheme = AuthenticationSchemes.Basic,
Realm = "XISOAPApps",
UseDefaultWebProxy = true
});
return result;
}
}
And I use it like this:
var service = new ServiceClient(new CustomHttpTransportBinding(), new EndpointAddress(url));
service.ClientCredentials.Windows.ClientCredential = new NetworkCredential("user", "password");
service.ClientCredentials.UserName.UserName = "user";
service.ClientCredentials.UserName.Password = "password";
var resp = service.Operation();
Console.WriteLine(resp.Response);
It reaches the server, but throws exception ("Server Error"), so I belive something wrong with my configuration. I can not specify the reader quotas also. I've tried loading configuration from string, but it is not worked for me, same error.
Confi
It seems that I can not convert custom bindings from XML to code in .net 3.5. Can somebody take a look on my code and confirm? Are there other ways to have a service client with custom binding in code?
I have not found a way to move configuration from app.config to code for a custom binding, it works greate for basicHttpBinding, but does not work for customBinding.
I've ended up with loading the configuration dynamicaly from file using custom chanell factory.
public class CustomChannelFactory<T> : ChannelFactory<T>
{
private readonly string _configurationPath;
public CustomChannelFactory(string configurationPath) : base(typeof(T))
{
_configurationPath = configurationPath;
base.InitializeEndpoint((string)null, null);
}
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint serviceEndpoint = base.CreateDescription();
ExeConfigurationFileMap executionFileMap = new ExeConfigurationFileMap();
executionFileMap.ExeConfigFilename = _configurationPath;
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(executionFileMap, ConfigurationUserLevel.None);
ServiceModelSectionGroup serviceModeGroup = ServiceModelSectionGroup.GetSectionGroup(config);
ChannelEndpointElement selectedEndpoint = null;
foreach (ChannelEndpointElement endpoint in serviceModeGroup.Client.Endpoints)
{
if (endpoint.Contract == serviceEndpoint.Contract.ConfigurationName)
{
selectedEndpoint = endpoint;
break;
}
}
if (selectedEndpoint != null)
{
if (serviceEndpoint.Binding == null)
{
serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, serviceModeGroup);
}
if (serviceEndpoint.Address == null)
{
serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);
}
if (serviceEndpoint.Behaviors.Count == 0 && !String.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration))
{
AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, serviceModeGroup);
}
serviceEndpoint.Name = selectedEndpoint.Contract;
}
return serviceEndpoint;
}
private Binding CreateBinding(string bindingName, ServiceModelSectionGroup group)
{
BindingCollectionElement bindingElementCollection = group.Bindings[bindingName];
if (bindingElementCollection.ConfiguredBindings.Count > 0)
{
IBindingConfigurationElement be = bindingElementCollection.ConfiguredBindings[0];
Binding binding = GetBinding(be);
if (be != null)
{
be.ApplyConfiguration(binding);
}
return binding;
}
return null;
}
private void AddBehaviors(string behaviorConfiguration, ServiceEndpoint serviceEndpoint, ServiceModelSectionGroup group)
{
EndpointBehaviorElement behaviorElement = group.Behaviors.EndpointBehaviors[behaviorConfiguration];
for (int i = 0; i < behaviorElement.Count; i++)
{
BehaviorExtensionElement behaviorExtension = behaviorElement[i];
object extension = behaviorExtension.GetType().InvokeMember("CreateBehavior",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, behaviorExtension, null);
if (extension != null)
{
serviceEndpoint.Behaviors.Add((IEndpointBehavior)extension);
}
}
}
private EndpointIdentity GetIdentity(IdentityElement element)
{
EndpointIdentity identity = null;
PropertyInformationCollection properties = element.ElementInformation.Properties;
if (properties["userPrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateUpnIdentity(element.UserPrincipalName.Value);
}
if (properties["servicePrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateSpnIdentity(element.ServicePrincipalName.Value);
}
if (properties["dns"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateDnsIdentity(element.Dns.Value);
}
if (properties["rsa"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateRsaIdentity(element.Rsa.Value);
}
if (properties["certificate"].ValueOrigin != PropertyValueOrigin.Default)
{
X509Certificate2Collection supportingCertificates = new X509Certificate2Collection();
supportingCertificates.Import(Convert.FromBase64String(element.Certificate.EncodedValue));
if (supportingCertificates.Count == 0)
{
throw new InvalidOperationException("UnableToLoadCertificateIdentity");
}
X509Certificate2 primaryCertificate = supportingCertificates[0];
supportingCertificates.RemoveAt(0);
return EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate, supportingCertificates);
}
return identity;
}
private Binding GetBinding(IBindingConfigurationElement configurationElement)
{
if (configurationElement is CustomBindingElement)
return new CustomBinding();
else if (configurationElement is BasicHttpBindingElement)
return new BasicHttpBinding();
else if (configurationElement is NetMsmqBindingElement)
return new NetMsmqBinding();
else if (configurationElement is NetNamedPipeBindingElement)
return new NetNamedPipeBinding();
else if (configurationElement is NetPeerTcpBindingElement)
return new NetPeerTcpBinding();
else if (configurationElement is NetTcpBindingElement)
return new NetTcpBinding();
else if (configurationElement is WSDualHttpBindingElement)
return new WSDualHttpBinding();
else if (configurationElement is WSHttpBindingElement)
return new WSHttpBinding();
else if (configurationElement is WSFederationHttpBindingElement)
return new WSFederationHttpBinding();
return null;
}
}
Usefull links:
Loading WCF configuration from different files (source code is not availiable)
Thread with source code of CustomChannelFactory
.NET 4.0 ChanellFactory (wish it was in .net 3.5)
Found an issue with the code referenced in boades reply, in that if you have mixed transport bindings (https/http) under basicHttpbinding you are likely to get an exception similar/reverse of this:
The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via
I'd also expect you will also have unexpected authorization occurring, again as the code will use the first bindingConfiguration listed in the web.config rather than by name.
The offending line which doesn't take the binding by name, but rather just takes the 1st one(!)
IBindingConfigurationElement be = bindingElementCollection.ConfiguredBindings[0];
This could be corrected by updating CreateBinding method and the call in CreateDescription like so:
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint description = base.CreateDescription();
if (CustomisedChannelFactory<TChannel>.ConfigurationPath == null || !System.IO.File.Exists(CustomisedChannelFactory<TChannel>.ConfigurationPath))
return base.CreateDescription();
ServiceModelSectionGroup sectionGroup = ServiceModelSectionGroup.GetSectionGroup(ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap()
{
ExeConfigFilename = CustomisedChannelFactory<TChannel>.ConfigurationPath
}, ConfigurationUserLevel.None));
ChannelEndpointElement channelEndpointElement1 = (ChannelEndpointElement)null;
foreach (ChannelEndpointElement channelEndpointElement2 in (ConfigurationElementCollection)sectionGroup.Client.Endpoints)
{
if (channelEndpointElement2.Contract == description.Contract.ConfigurationName)
{
channelEndpointElement1 = channelEndpointElement2;
break;
}
}
if (channelEndpointElement1 != null)
{
if (description.Binding == null)
description.Binding = this.CreateBinding(channelEndpointElement1.Binding, channelEndpointElement1.BindingConfiguration, sectionGroup);
if (description.Address == (EndpointAddress)null)
description.Address = new EndpointAddress(channelEndpointElement1.Address, this.GetIdentity(channelEndpointElement1.Identity), channelEndpointElement1.Headers.Headers);
if (description.Behaviors.Count == 0 && !string.IsNullOrEmpty(channelEndpointElement1.BehaviorConfiguration))
this.AddBehaviors(channelEndpointElement1.BehaviorConfiguration, description, sectionGroup);
description.Name = channelEndpointElement1.Contract;
}
return description;
}
private Binding CreateBinding(string bindingName, string bindingConfigurationName, ServiceModelSectionGroup group)
{
BindingCollectionElement collectionElement = group.Bindings[bindingName];
if (collectionElement.ConfiguredBindings.Count <= 0)
return (Binding)null;
IBindingConfigurationElement configurationElement = null;
foreach (IBindingConfigurationElement bce in collectionElement.ConfiguredBindings)
{
if (bce.Name.Equals(bindingConfigurationName))
{
configurationElement = bce;
break;
}
}
if (configurationElement == null) throw new Exception("BindingConfiguration " + bindingConfigurationName + " not found under binding " + bindingName);
Binding binding = this.GetBinding(configurationElement);
if (configurationElement != null)
configurationElement.ApplyConfiguration(binding);
return binding;
}

Categories