I've been doing tests using the following sample from Microsoft :
http://msdn.microsoft.com/en-us/library/ff521581.aspx
it works, but it is a basichttp endpoint.
is there a way to make it a CustomBinding endpoint with binaryMessageEncoding?
Thanks,
Alex
This will create a custom binding using Http transport and binary encoding:
protected override Binding CreateBinding()
{
BinaryMessageEncodingBindingElement messageEncoding = new BinaryMessageEncodingBindingElement();
TransportBindingElement transport = new HttpTransportBindingElement();
BindingElementCollection bindingElements = new BindingElementCollection()
{
messageEncoding, transport
};
return new CustomBinding(bindingElements);
}
Related
I add a reference to a service in my .net core 2.2 project using svcutil 2.0.2 from here :
http://sms.magfa.com/services/urn:SOAPSmsQueue?wsdl
the created service proxy send the request to server and server send reply back to the us but the proxy can not get the result !!
we use this service in our asp .net web app but in .net core 2.2 using svcutil 2.0.2 we can not get the result.
what is the problem ?
thank you
my code :
BasicHttpBinding basicHttpBinding = null;
EndpointAddress endpointAddress = null;
ChannelFactory<ServiceReference1.SoapSmsQueuableImplChannel> factory = null;
ServiceReference1.SoapSmsQueuableImplChannel serviceProxy = null;
try
{
basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
endpointAddress = new EndpointAddress(new Uri("https://sms.magfa.com/services/urn:SOAPSmsQueue?wsdl"));
factory = new ChannelFactory<ServiceReference1.SoapSmsQueuableImplChannel>(basicHttpBinding, endpointAddress);
factory.Credentials.UserName.UserName = "**";
factory.Credentials.UserName.Password = "****";
serviceProxy = factory.CreateChannel();
//((ICommunicationObject)serviceProxy).Open();
//var opContext = new OperationContext((IClientChannel)serviceProxy);
//var prevOpContext = OperationContext.Current; // Optional if there's no way this might already be set
//OperationContext.Current = opContext;
using (var scope = new OperationContextScope((IContextChannel)serviceProxy))
{
var result = await serviceProxy.getCreditAsync("***").ConfigureAwait(false);
}
factory.Close();
((ICommunicationObject)serviceProxy).Close();
}
catch (MessageSecurityException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
finally
{
// *** ENSURE CLEANUP (this code is at the WCF GitHub page *** \\
CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
}
I tried to emit an http header but somehow wcf filters it.
[ServiceContract()]
public interface IHelloWorld
{
[OperationContract(Action = "*", IsOneWay = false, ReplyAction = "*")]
void Hello(string text);
}
var channel = new ChannelFactory<IHelloWorld>(new WebHttpBinding(), "http://some.where");
channel.Endpoint.Behaviors.Add(new WebHttpBehavior());
var proxy = channel.CreateChannel();
using (OperationContextScope scope = new OperationContextScope((IContextChannel)proxy))
{
MessageProperties messageProperties = OperationContext.Current.OutgoingMessageProperties;
var requestMessageProperty = new HttpRequestMessageProperty();
messageProperties.Add(HttpRequestMessageProperty.Name, requestMessageProperty);
requestMessageProperty.Headers.Add("SOAPAction", "test");
requestMessageProperty.Headers.Add("Test", "test2");
proxy.Hello("test");
}
When testing this code, the header Test is in the request but SOAPAction is not.
I tried with a IClientMessageInspector but it doesn't work either.
I cannot use another binding (Basic or a more Soap dedicated one).
As far as I know the SOAPAction field is the HTTP header default field and is used to indicate that the action method being invoked when server service uses a non-webhttpbinding.
I don't think it could be arbitrarily specified by intercepting the message/operation context.
I am trying to use DataContractResolver as an alternative to KnownTypes in WCF.
I have the following code and I've used it before on the server side. But on the client side, the code returns null when trying to find DataContractSerializerOperationBehavior in operation behaviors collection.
public override IMyService CreateProxy(Uri url)
{
ServiceEndpoint endpoint = CreateEndpoint(url);
var channelFactory = new ChannelFactory<IMyService>(endpoint);
InjectResolver(channelFactory.Endpoint);
return channelFactory.CreateChannel();
}
private void InjectResolver(ServiceEndpoint endpoint)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
var behavior = operation.Behaviors.Find<DataContractSerializerOperationBehavior>();
behavior.DataContractResolver = new DerivedTypeResolver(); // behavior is null here!
}
}
Why is the behavior missing?
UPDATE: I found out the real issue is that WCF was using XmlSerializer instead of DataContractSerializer. Is there a way to force a DataContractSerializer instead? Does WCF choose the serializer based on the wsdl? Considering I don't (yet) have the capacity to change the server side, what is my option? XmlSerializer behavior doesn't seem to have a similar option of resolving the type myself.
See here for example on how to create DataContractSerializerOperationBehavior if it does not exist:
private void DataContractBehavior()
{
WSHttpBinding b = new WSHttpBinding(SecurityMode.Message);
Uri baseAddress = new Uri("http://localhost:1066/calculator");
ServiceHost sh = new ServiceHost(typeof(Calculator), baseAddress);
sh.AddServiceEndpoint(typeof(ICalculator), b, "");
// Find the ContractDescription of the operation to find.
ContractDescription cd = sh.Description.Endpoints[0].Contract;
OperationDescription myOperationDescription = cd.Operations.Find("Add");
// Find the serializer behavior.
DataContractSerializerOperationBehavior serializerBehavior =
myOperationDescription.Behaviors.
Find<DataContractSerializerOperationBehavior>();
// If the serializer is not found, create one and add it.
if (serializerBehavior == null)
{
serializerBehavior = new DataContractSerializerOperationBehavior(myOperationDescription);
myOperationDescription.Behaviors.Add(serializerBehavior);
}
// Change the settings of the behavior.
serializerBehavior.MaxItemsInObjectGraph = 10000;
serializerBehavior.IgnoreExtensionDataObject = true;
sh.Open();
Console.WriteLine("Listening");
Console.ReadLine();
}
example from https://msdn.microsoft.com/en-us/library/system.servicemodel.description.datacontractserializeroperationbehavior.aspx
I have a Self-Hosted WCF Service and client.
The client does not have a service reference, I have linked it to the endpoint programmatically.
The bindings are set to BasicHttpBinding in both the client and service -
Service
Uri baseAddress = new Uri("http://localhost:8733/Design_Time_Addresses/DSCentralService/Service1/");
DSCentralService.Service1 contentServer = new DSCentralService.Service1();
//initialise the servicehost
centralSvrHost = new ServiceHost(typeof(DSCentralService.Service1), baseAddress);
//add bindings
centralSvrHost.AddServiceEndpoint(
typeof(DSCentralService.IService1),
new BasicHttpBinding(),
baseAddress
);
Client
serviceFactory = new ServiceFactory<DSCentralService.IService1>();
String serviceAddress="http://localhost:8733/Design_Time_Addresses/DSCentralService/Service1/";
iContentServer = serviceFactory.GetService(serviceAddress);
Service Factory Class
public class ServiceFactory<T> where T : class
{
private T _service;
public T GetService(string address)
{
return _service ?? (_service = GetServiceInstance(address));
}
private static T GetServiceInstance(string address)
{
BasicHttpBinding basicBinding = new BasicHttpBinding();
basicBinding.Name = "DSCentralSvr";
basicBinding.TransferMode = TransferMode.Streamed;
basicBinding.MessageEncoding = WSMessageEncoding.Mtom;
basicBinding.MaxReceivedMessageSize = 10067108864;
basicBinding.SendTimeout = new TimeSpan(0, 10, 0);
basicBinding.OpenTimeout = new TimeSpan(0, 10, 0);
basicBinding.CloseTimeout = new TimeSpan(0, 10, 0);
basicBinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
EndpointAddress endpoint = new EndpointAddress(address);
return ChannelFactory<T>.CreateChannel(basicBinding, endpoint);
}
}
Yet upon debugging, I receive the common error of
The client and service bindings may be mismatched
There are no settings for bindings in any config files of either the client or service, to avoid conflicts with the programmatic settings.
Is there something I have missed, which is necessary when doing this programmatically? What is causing this mis-match?
You are hosting the service with a default BasicHttpBinding which means TransferMode Buffered and MessageEncoding Text.
In your client you are using Streamed and Mtom, respectively.
I'd like to convert my current HTTP/HTTPS WCF binding settings to use binary message encoding and I need to do it in code - not in XML configuration. AFAIK it's necessary to create CustomBinding object and set proper BindingElements, but I'm not able to figure out what elements should I use in my scenario.
Main points in my WCF configuration are:
use HTTP or HTTPS transport depending on configuration (in app.config)
use username message security
todo: add binary encoding instead of default text
My current code for setting the binding up (working, but without the binary encoding):
var isHttps = Settings.Default.wcfServiceBaseAddress.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase);
var binding = new WSHttpBinding(isHttps ? SecurityMode.TransportWithMessageCredential : SecurityMode.Message);
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
I was trying this code, but it doesn't work - I don't know how to set message security element for username message security:
var custBinding = new CustomBinding();
custBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
//Transport Security (Not Required)
if (isHttps)
{
custBinding.Elements.Add(SecurityBindingElement.CreateUserNameForSslBindingElement());
}
//Transport (Required)
custBinding.Elements.Add(isHttps ?
new HttpsTransportBindingElement() :
new HttpTransportBindingElement());
Anybody knows how to set this up? I tried to search for similar problem/solution, but didn't succeeded...
I almost forgot this question, but here is my custom binding class which works with binary binding over HTTP with username+password validation and also allows to turn GZip compression on...
public class CustomHttpBinding: CustomBinding
{
private readonly bool useHttps;
private readonly bool useBinaryEncoding;
private readonly bool useCompression;
private readonly HttpTransportBindingElement transport;
public CustomHttpBinding(bool useHttps, bool binaryEncoding = true, bool compressMessages = false)
{
this.useHttps = useHttps;
transport = useHttps ? new HttpsTransportBindingElement() : new HttpTransportBindingElement();
useBinaryEncoding = binaryEncoding;
useCompression = compressMessages;
}
public long MaxMessageSize{set
{
transport.MaxReceivedMessageSize = value;
transport.MaxBufferSize = (int) value;
}}
public override BindingElementCollection CreateBindingElements()
{
BindingElement security;
if (useHttps)
{
security = SecurityBindingElement.CreateSecureConversationBindingElement(
SecurityBindingElement.CreateUserNameOverTransportBindingElement());
}
else
{
security = SecurityBindingElement.CreateSecureConversationBindingElement(
SecurityBindingElement.CreateUserNameForSslBindingElement(true));
}
MessageEncodingBindingElement encoding;
if (useCompression)
{
encoding = new GZipMessageEncodingBindingElement(useBinaryEncoding
? (MessageEncodingBindingElement)
new BinaryMessageEncodingBindingElement()
: new TextMessageEncodingBindingElement());
}
else
{
encoding = useBinaryEncoding
? (MessageEncodingBindingElement) new BinaryMessageEncodingBindingElement()
: new TextMessageEncodingBindingElement();
}
return new BindingElementCollection(new[]
{
security,
encoding,
transport,
});
}
}
The SecurityBindingElement has a AllowInsecureTransport property. If you set this to true you can use the HttpTransportBindingElement with message user name and password security.
Try SecurityBindingElement.CreateUserNameOverTransportBindingElement() instead:
var custBinding = new CustomBinding();
custBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
//Transport Security (Not Required)
if (isHttps)
{
custBinding.Elements.Add(SecurityBindingElement.CreateUserNameOverTransportBindingElement());
}
//Transport (Required)
custBinding.Elements.Add(isHttps ?
new HttpsTransportBindingElement() :
new HttpTransportBindingElement());