Currently we are moving away from Castle Windsor container and I've been struggling to find examples of how to inject WCF client into service collection in .NET Core Startup.cs. Does anybody know how to do that with passing endpoint and credentials?
Here is how it was done for Castle Windsor container:
container.Register(Component.For<IUserServiceV1>()
.AsWcfClient(new DefaultClientModel
{
Endpoint = WcfEndpoint.BoundTo(new BasicHttpsBinding(BasicHttpsSecurityMode.TransportWithMessageCredential) { MaxReceivedMessageSize = 2147483647, ReceiveTimeout = new TimeSpan(0, 0, 5, 0), CloseTimeout = new TimeSpan(0, 0, 5, 0), OpenTimeout = new TimeSpan(0, 0, 5, 0), SendTimeout = new TimeSpan(0, 0, 5, 0) })
.At($"{userService.Url}/Services/UserService.svc")
}
.Credentials(new Castle.Facilities.WcfIntegration.Behaviors.UserNameCredentials(userService.Username, userService.Password)))
.LifestyleTransient());
I would like to do that using .NET Core Microsoft.Extensions.DependencyInjection.
From the code snippets, the WCF service on the server-side is created by BasichttpsBinding with TransportWithMessageCredential security mode and authenticates the client with username/password.
As far as I know, it is not compatible with the Asp.net Core project. Namely, it cannot be consumed properly in the Asp.net Core project. so it is not feasible.
Official repository.
https://github.com/dotnet/wcf/issues/8
I would like to know more details about the service on the server-side.
Feel free to let me know if there is anything I can help with.
I'm fairly recent to WCF and trying to figure out the best way to accomplish my requirements.
I have an application hosting a WCF service with the following code:
Uri u1 = new
Uri("http://localhost:8732/Client1/WcfServiceLibrary1/Service1/"); Uri
u2 = new
Uri("http://localhost:8732/Client1/WcfServiceLibrary1/Service1/mex");
WSHttpBinding binding = new WSHttpBinding();
sHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1), u1);
ServiceMetadataBehavior meta = new ServiceMetadataBehavior();
meta.HttpGetEnabled = true;
sHost.AddServiceEndpoint(typeof(WcfServiceLibrary1.IService1), binding, u1);
sHost.Description.Behaviors.Add(meta); sHost.Open();
I can create a service reference on a client application and call methods on this service no problems. using the code below.
remoteService.Service1Client client = new remoteService.Service1Client();
remote.Text = client.GetData(3);
I can also call a method without a service reference.
EndpointAddress myEndpoint = new EndpointAddress("http://localhost:8732/Client1/WcfServiceLibrary1/Service1/");
WSHttpBinding myBinding = new WSHttpBinding();
ChannelFactory<IService1> ServiceConnectionFactory = new ChannelFactory<IService1>(myBinding, myEndpoint);
IService1 serviceConnection = ServiceConnectionFactory.CreateChannel();
If I try to execute the same code in the host application it get the error below.
The request channel timed out while waiting for a reply after
00:01:00. Increase the timeout value passed to the call to Request or
increase the SendTimeout value on the Binding. The time allotted to
this operation may have been a portion of a longer timeout.
How can a application consume and use a WCF service that it is currently hosting? Do I need to open the service in a thread of its own?
The idea is for the host to trigger some initialization before clients connect.
I'm writing a WCF Client that consumes a non-.Net web service, using WS-Security. The service's response contains a Security header with mustUnderstand set to true.
Using a ServiceModelListener, I do see actual data coming back from the service. The WCF client fails, however, because it is not processing the Security header.
<env:Header>
<wsse:Security env:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Timestamp wsu:Id="timestamp">
<wsu:Created>2012-03-28T13:43:54.474Z</wsu:Created>
<wsu:Expires>2012-03-28T13:48:54.474Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</env:Header>
WCF Client Error Message:
The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding.
My WCF client doesn't need any of the timestamp info. Is there an easy way to stub in a processing routine? I've already tried extending the Response class & adding a [MessageHeader] property.
EDIT:
Asked another way: How do I implement a WCF client that accepts custom header elements that are marked Must Understand?
I ran into a similar issue. I am not sure if this is useful or not.
MSDN WCF Extensibility
http://blogs.msdn.com/b/carlosfigueira/archive/2011/04/19/wcf-extensibility-message-inspectors.aspx
The setup here is Certificate based, Oracle Application Server 10g, and .Net to consume the services. Using SOAPUi was very useful while trying to figure out what was happening with the Request and then the response.
I have not tried modifying the code to use basicHttpBinding, but I used WSHttpBinding as the base of my configuration in code. Then used
WSHttpBinding binding = new WSHttpBinding()
{
CloseTimeout = new TimeSpan(0, 1, 0),
OpenTimeout = new TimeSpan(0, 1, 0),
SendTimeout = new TimeSpan(0, 1, 0),
AllowCookies = false,
BypassProxyOnLocal = false,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
MaxBufferPoolSize = 524288,
MaxReceivedMessageSize = 65536,
MessageEncoding = WSMessageEncoding.Text,
UseDefaultWebProxy = false,
ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxDepth = 32,
MaxArrayLength = 16384,
MaxBytesPerRead = 4096,
MaxNameTableCharCount = 16384,
MaxStringContentLength = 8192
}
};
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
binding.Security.Transport.Realm = string.Empty;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
binding.Security.Message.EstablishSecurityContext = true;
binding.Security.Message.NegotiateServiceCredential = true;
CustomBinding customBinding = new CustomBinding();
BindingElementCollection collection = binding.CreateBindingElements();
Looped through for the TextMessageEncodingBindingElement to set Soap11 and AddressingVersion to None.
foreach (BindingElement element in collection)
{
if (typeof(TextMessageEncodingBindingElement) == element.GetType())
{
TextMessageEncodingBindingElement item = element as TextMessageEncodingBindingElement;
if (null != item)
{
item.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap11, AddressingVersion.None);
customBinding.Elements.Add(item);
}
}
else
customBinding.Elements.Add(element);
}
I used the ChannelFactory and added an EndPoint Behavior for a Message Inspector.
At this point I then had control of the request and I could add the appropriate header and modified the mustUnderstand on the Action.
Using SOAPUi I took my Message.ToString() and put that in SOAPUI and tested the request. Once the items that were needed were added to the request, it was then determined that the OAS server was not replying with all the necessary elements. Using the message inspector for the reply I modified the message to include the missing headers. I can't remember where I found the base code for the message inspector, but you would need to modify your code to utlize it properly.
For my example here are some snippets.
For the transform message in
public object BeforeSendRequest
I needed to modify the Header, so using a for loop I grabbed the XElement and added the OASIS header and added a To header.
XNamespace xmlns = "http://schemas.xmlsoap.org/soap/envelope/";
XElement securityHeader = new XElement(
xmlns + "Security",
new XAttribute(xmlns + "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"),
new XAttribute(xmlns + "xmlns", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"),
new XAttribute(xmlns + "mustUnderstand", "0"));
element.Add(securityHeader);
I also had to modify the Action Header
else if (localName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
{
foreach (XAttribute a in element.Attributes())
{
if (a.Name.LocalName == "mustUnderstand")
a.Value = "0";
}
}
My problem was that the Service didn't reply with an Action Header
So in the
public void AfterReceiveReply
I called my TransformReply returning type Message with something like the following. You may need to modify values for the string.Empty, but this is just an example.
...
Message reply = Message.CreateMessage(message.Version, null, reader);
reply.Headers.Add(MessageHeader.CreateHeader("Action", string.Empty, string.Empty, false));
reply.Properties.CopyProperties(message.Properties);
...
I would really suggest using a tool such as SOUPUI to beable to mess with the envelope and see the reply. If you do SSL, you'll need to create a cacert file and place it in the SSLSettings of the preferences.
There is different standards of WS-Security. Might be it make sense to change the binding at client side, since basicHttpBinding and wsHttpBindings are working with different security standards.
Ran into an issue working on some code around IP cameras supporting ONVIF. Cameras were sending back Nonce and Created in Security element and WCF didn't like it. Ended up using IClientMessageInspector to catch the response, and re-flag the header as mustUnderstand=false.
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//Some cameras produce WS-Security headers as a repsonse which contain a nonce and created date/time WCF doesn't like this for some reason.
//The WS-Security element contains mustUnderstand="true". When WCF can't process the unrecoginzed elements it throw an exception.
// The code below searches for a WS-Security header. If one is found it copies the message body and all headers but the WS-Security header.
// A new WS-Security header is then created with mustUnderstand=false and added into the new message. The proxy clients
// will still receive the WS-Security header, just won't throw exceptions because of Nonce and Created elements in the header.
if (reply.Headers.Count > 0)
{
//Have a WS-Security header?
int secHeaderIndex = reply.Headers.FindHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
if (secHeaderIndex < 0) { return; }
//Our replacement message
System.ServiceModel.Channels.Message cleanedMessage = null;
//Copy the body
cleanedMessage = Message.CreateMessage(reply.Version, "", reply.GetReaderAtBodyContents());
//Create a new WS-Security header with mustUnmderstand=false
MessageHeader newSecHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", reply.Headers[0], false);
for (int x=0; x<reply.Headers.Count; x++)
{
if (x == secHeaderIndex)
{//Don't copy the old WS-Security header
continue;
}
//Not a WS-Security header, copy to the new message.
cleanedMessage.Headers.CopyHeaderFrom(reply, x);
}
cleanedMessage.Headers.Add(newSecHeader);
reply = cleanedMessage;
}
}
I have a class that implements a plugin for an existing application.
I also have exposed that class as a WCF service. That part is working so far. The problem I am running into is that the application I am plugging into creates the instance of my class that I want to use.
Is there a way to pass an existing class instance to the WCF service host, to expose as a service endpoint?
I know (or can figure out) how to make a singleton instance of a WCF service, but that still won't help me. From what I can tell, the singleton instance will still be created and provided by WCF.
I have thought of other approaches, but I'd rather take this one if it is available to me.
Some code. This is in the constructor of my plugin:
// Setup the service host
var baseAddress = new Uri("http://localhost:8080/MyService/");
this.serviceHost = new ServiceHost(this.GetType(), baseAddress);
// Add our service endpoint
// Todo: Is there somewhere around here that I can provide an instance?
// Maybe in behavior somewhere?
this.serviceHost.AddServiceEndpoint(
typeof(ITheInterfaceMyClassDerivesFrom),
new BasicHttpBinding(),
""
);
// Add metadata exchange (so we see something when we go to that URL)
var serviceMetadataBehavior = this.serviceHost.Description.Behaviors
.Find<ServiceMetadataBehavior>();
if (serviceMetadataBehavior == null)
this.serviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior());
this.serviceHost.AddServiceEndpoint(
typeof(IMetadataExchange),
new CustomBinding(new HttpTransportBindingElement()),
"MEX"
);
This is in the plugin's OnStartedUp method (called by the application I am plugging into):
serviceHost.Open();
You need to use the other constructor for ServiceHost if you want to do this - check out the MSDN docs at http://msdn.microsoft.com/en-us/library/ms585487.aspx
public ServiceHost(
Object singletonInstance,
params Uri[] baseAddresses
)
I'd like to configure a NetTcpBinding programatically for a silverlight 4 client. (NetTcpBinding is now supported)
Here is the code I use to do this for a Windows Forms client:
EndpointAddress endpointAddress = new EndpointAddress(uri);
NetTcpBinding netTcpBinding = new NetTcpBinding();
MyServiceClient agentClient = new MyServiceClient(new InstanceContext(this), netTcpBinding, endpointAddress);
For silverlight I added references to System.ServiceModel.Extensions and System.ServiceModel.NetTcp, but this is not not enough : I'm not able to find a NetTcpBinding class.
Where is this class if it exists? Does an equivalent syntax exists? The silverlight 4 runtime must be doing this somehow when a configuration file is used.
You can use a custom binding in place of NetTcpBinding : the code below is working, but I don't know if this is the recommended pattern.
BinaryMessageEncodingBindingElement messageEncoding = new BinaryMessageEncodingBindingElement();
TcpTransportBindingElement tcpTransport = new TcpTransportBindingElement();
CustomBinding binding = new CustomBinding(messageEncoding, tcpTransport);