DataContractSerializerOperationBehavior is not found when trying to use DataContractResolver - wcf

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

Related

Apache CXF Password Type Always Sets Digest

I am working on a web service client project and using Apache CXF to send request to web service.
I need to set passwordType as PasswordText. But even if I set it in OutInterceptor property, It always sets passwordType as Digest. How can I solve this issue?
My Code is this:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(Test.class);
factory.setAddress(url);
factory.getInInterceptors().add(new SoapActionInInterceptor(action));
factory.getOutInterceptors().add(new SoapActionOutInterceptor());
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
outProps.put(WSHandlerConstants.USER, username);
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PASSWORD_TEXT);
ClientPasswordHandler handler = new ClientPasswordHandler();
handler.setPassword(password);
outProps.put(WSHandlerConstants.PW_CALLBACK_REF, handler);
WSS4JStaxOutInterceptor wssOut = new WSS4JStaxOutInterceptor(outProps);
factory.getOutInterceptors().add(wssOut);
T serviceClient = (T) factory.create();
Client client = ClientProxy.getClient(serviceClient);
setClientPolicy(client);
And clientPolicy is this
protected synchronized void setClientPolicy(Client client) {
if (client != null) {
HTTPConduit httpConduit = (HTTPConduit) client.getConduit();
httpConduit.setAuthSupplier(null);
httpConduit.setAuthorization(null);
HTTPClientPolicy clientPolicy = new HTTPClientPolicy();
clientPolicy.setConnectionTimeout(60000L);
clientPolicy.setReceiveTimeout(60000L);
httpConduit.setClient(clientPolicy);
}
}
org.apache.cxf -> version 3.1.6
org.apache.wss4j -> version 2.1.7
I have found the solution. WSS4JStaxOutInterceptor extends AbstractWSS4JStaxInterceptor and it has a function to set incoming properties which we have send. When it try to set password property it checks incoming property with "PasswordText" string and when we use WSConstants its value is different. That's why when we set property value with "PasswordText" string it works fine. Final code for interceptor is:
private WSS4JStaxOutInterceptor createSecurityInterceptor() {
Map<String, Object> outProps = new HashMap<>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
outProps.put(WSHandlerConstants.USER, username);
// AbstractWSS4JStaxInterceptor class parseNonBooleanProperties require "PasswordText" check this function before changing this line
outProps.put(WSHandlerConstants.PASSWORD_TYPE, "PasswordText");
// AbstractWSS4JStaxInterceptor class parseNonBooleanProperties require "PasswordText" check this function before changing this line
ClientPasswordHandler handler = new ClientPasswordHandler();
handler.setPassword(password);
outProps.put(WSHandlerConstants.PW_CALLBACK_REF, handler);
return new WSS4JStaxOutInterceptor(outProps);
}
This solves the issue.

Dealing with Azure staging crazy URL

i'm deploying a webrole in azure that contains a web-site and a wcf service...
The site consumes services from the wcf.
The problem here is that the staging deploy creates a crazy url for the endpoints and i have to keep changing the endpoints in the web.config...
I'm wondering if theres a way to either "predict" what the url will be or to force one or even point to a generic host such as "localhost"???
You should be able to use role discovery to find the WCF endpoint. See this SO answer here and the blog post it links to.
My own abstract base class for connecting to azure services was based on that article. It uses role discovery to crate a channel like this:
#region Channel
protected String roleName;
protected String serviceName;
protected String endpointName;
protected String protocol = #"http";
protected EndpointAddress _endpointAddress;
protected BasicHttpBinding httpBinding;
protected NetTcpBinding tcpBinding;
protected IChannelFactory channelFactory;
protected T client;
protected virtual AddressHeader[] addressHeaders
{
get
{
return null;
}
}
protected virtual EndpointAddress endpointAddress
{
get
{
if (_endpointAddress == null)
{
var endpoints = RoleEnvironment.Roles[roleName].Instances.Select(i => i.InstanceEndpoints[endpointName]).ToArray();
var endpointIP = endpoints.FirstOrDefault().IPEndpoint;
if(addressHeaders != null)
{
_endpointAddress = new EndpointAddress(new Uri(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName)), addressHeaders);
}
else
{
_endpointAddress = new EndpointAddress(String.Format("{1}://{0}/{2}", endpointIP, protocol, serviceName));
}
}
return _endpointAddress;
}
}
protected virtual Binding binding
{
get
{
switch (protocol)
{
case "tcp.ip":
if (tcpBinding == null) tcpBinding = new NetTcpBinding();
return tcpBinding;
default:
//http
if (httpBinding == null) httpBinding = new BasicHttpBinding();
return httpBinding;
}
}
}
public virtual T Client
{
get
{
if (this.client == null)
{
this.channelFactory = new ChannelFactory<T>(binding, endpointAddress);
this.client = ((ChannelFactory<T>)channelFactory).CreateChannel();
((IContextChannel)client).OperationTimeout = TimeSpan.FromMinutes(2);
var scope = new OperationContextScope(((IContextChannel)client));
addCustomMessageHeaders(scope);
}
return this.client;
}
}
#endregion
And in a derived class I pass it the following variables (for example):
this.roleName = "WebServiceRole";
this.endpointName = "HttpInternal";
this.serviceName = "services/Accounts.svc";
I never need to refer to the staging (or production) URLs at all.
See my answer here for more details: Add WCF reference within the same solution without adding a service reference
There is no way to either predict the GUID, control it, or use some constant name.
What you can do, to make things easier, is to move the URL into .CSCFG and update the URL of the WCF service from Azure Management Portal

RestSharp post object to WCF

I am having an issue posting an object to my WCF REST Web Service.
On the WCF side I have the following:
[WebInvoke(UriTemplate = "", Method = "POST")]
public void Create(myObject object)
{
//save some stuff to the db
}
When I am debugging, the break point is never hit.However, the break point is hit when I remove the parameter.So, I am guessing I have done something wrong on the RestSharp side of things.
Here's my code for that part:
var client = new RestClient(ApiBaseUri);
var request = new RestRequest(Method.POST);
request.RequestFormat = DataFormat.Xml;
request.AddBody(myObject);
var response = client.Execute(request);
Am I doing this wrong? How can the WCF side see my object? What way should I be making the request? Or should I be handling it differently on the WCF side?
Things that I have tried:
request.AddObject(myObject);
and
request.AddBody(request.XmlSerialise.serialise(myObject));
Any help and understanding in what could possibly be wrong would be much appreciated. Thanks.
I have been struggling with the same problem. Once you try to add the object to pass, it becomes a "Bad request". I tried a variety of things based on various sites I found and got nothing. Then I changed the format from Xml to Json, and it just started working. Must be some glitch with XML passing. Might need to setup a 2nd PC and try to sniff the actual http with something like wireshark or fiddler. (Or maybe I'll just stick to json)
Below is the function from my experimental WCF interface
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "manualselect", ResponseFormat = WebMessageFormat.Json)]
void PostManualSelect(ManualUpdateRequest S);
then my test RestSharp client
var client = new RestClient();
client.BaseUrl = "http://127.0.0.1:8000";
/* Initialization of ManualUpdateRequest instance "DR" here */
var request = new RestRequest(Method.POST);
request.Resource = "manualselect";
request.RequestFormat = DataFormat.Json;
request.AddBody(DR);
RestResponse response = client.Execute(request);
Perhaps someone can shed some more light on the matter. I am also new to REST services. I'd thought I'd add my findings to steer towards a better answer.
(--EDIT--)
I did some more digging and found this tidbit
So I added the [XmlSerializerFormat] attribute to ServiceContract interface like so
[ServiceContract]
[XmlSerializerFormat]
public interface IMyRestService
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "manualselect", ResponseFormat = WebMessageFormat.Xml)]
void PostManualSelect(ManualUpdateRequest S);
}
and then this finally worked and I got an object in my service
var client = new RestClient();
client.BaseUrl = "http://127.0.0.1:8000";
/* Initialization of ManualUpdateRequest instance "DR" here */
var request = new RestRequest(Method.POST);
request.Resource = "manualselect";
request.RequestFormat = DataFormat.Xml;
request.AddBody(DR);
RestResponse response = client.Execute(request);
(--EDIT 2--) I have encountered some more XML serializing weirdness that lead me to make this extension (borrowing from here). Might help if you still have trouble. There is also an answer here that implies you need to use public properties to serialize correctly, which I have not tried yet.
public static class RestSharpExtensions
{
public static T GetXmlObject<T>(this IRestResponse response)
{
if (string.IsNullOrEmpty(response.Content))
{
return default(T);
}
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlReaderSettings settings = new XmlReaderSettings();
// No settings need modifying here
using (StringReader textReader = new StringReader(response.Content))
{
using (XmlReader xmlReader = XmlReader.Create(textReader, settings))
{
return (T)serializer.Deserialize(xmlReader);
}
}
}
public static void UseDotNetXml(this IRestRequest request)
{
request.RequestFormat = DataFormat.Xml;
request.XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer();
}
}
So my RestSharp calls start looking more like this
public SimpleSignUpdateDataSet GetSimpleDataset()
{
var client = new RestClient(SerivceURL);
var request = new RestRequest("simpledataset", Method.GET);
request.UseDotNetXml();
var resp = client.Execute(request);
return resp.GetXmlObject<SimpleSignUpdateDataSet>();
}
This answer is getting long, but I hope it is of some help to someone.
you can use fiddler on the same pc .... no need for a second one. If you install it, solving these types of problems gets really much easier, you see what you do!
Specify proxy like this:
using system.net; // for the WebProxy
RestClient rc = new RestClient(aUrl);
rc.Proxy = new WebProxy("http://127.0.0.1:8888");

WCF - how to create programatically custom binding with binary encoding over HTTP(S)

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());

How to create client proxy without svcutil or add service reference in wcf?

How can I create a client proxy without svcutil.exe or add service reference in wcf?
I want to create a client proxy at compile time.
If you have access to the service contract (the IService interface) in a separate DLL, you can add a reference to that service contract DLL and then do something like:
NetTcpBinding binding = new NetTcpBinding();
EndpointAddress address = new EndpointAddress("net.tcp://localhost:9000/YourService")
ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, address);
IService proxy = factory.CreateChannel();
and then you have your programmatically created proxy, which you can now use as you wish.
This might not be what you are looking for, but it's pretty interesting.
Vipul Modi has a library that allows you to call WCF services after downloading their WSDL, all at runtime.
Vipul Modi's library (latest version)
Allows you to do this kind of thing:
Create the ProxyFactory specifying the WSDL URI of the service.
DynamicProxyFactory factory = new DynamicProxyFactory("http://localhost:8080/WcfSamples/DynamicProxy?wsdl");
Browse the endpoints, metadata, contracts etc.
factory.Endpoints
factory.Metadata
factory.Contracts
factory.Bindings
Create DynamicProxy to an endpoint by specifying either the endpoint or
contract name.
DynamicProxy proxy = factory.CreateProxy("ISimpleCalculator");
//OR
DynamicProxy proxy = factory.CreateProxy(endpoint);
Invoke operations on the DynamicProxy
double result = (double)proxy.CallMethod("Add", 1d ,2d);
Close the DynamicProxy
proxy.Close();
You don't need to code generate (or use a configuration file full of WCF specifics).
First create the interface defining the service ([ServiceContract]) with any supporting data contracts in an assembly separate from the service implementation.
Reference the interface assembly in the client assembly.
Then need to create a client proxy, for IMyService:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(url);
ChannelFactory<IMyService> chanFac = new ChannelFactory<IMyService>(binding, endpoint);
IMyService clientProxy = chanFac.CreateChannel();
Here is the solution I have been using since wcf was introduced:
In an infrastructure assembly:
internal class PerCallDisposeRealProxy<T> : RealProxy where T : class
{
private readonly Binding _binding;
private readonly EndpointAddress _endpointAddress;
private static string EndpointName
{
get
{
string endpointName = typeof(T).Name;
if (endpointName.StartsWith("I"))
{
endpointName = endpointName.Substring(1);
}
return endpointName;
}
}
internal PerCallDisposeRealProxy()
: base(typeof(T))
{
}
internal PerCallDisposeRealProxy(Binding binding, EndpointAddress endpointAddress)
: base(typeof(T))
{
if (binding == null)
throw new ArgumentNullException("binding");
if (endpointAddress == null)
throw new ArgumentNullException("endpointAddress");
_binding = binding;
_endpointAddress = endpointAddress;
}
private ChannelFactory<T> CreateChannel()
{
if (_binding != null && _endpointAddress != null)
return new ChannelFactory<T>(_binding, _endpointAddress);
else
return new ChannelFactory<T>(EndpointName);
}
[DebuggerStepThrough]
public override IMessage Invoke(IMessage message)
{
if (message == null) throw new ArgumentNullException("message");
//Extract method info
var methodCall = message as IMethodCallMessage;
Debug.Assert(methodCall != null);
MethodInfo methodInfo = methodCall.MethodBase as MethodInfo;
Debug.Assert(methodInfo != null);
T channel = null;
ChannelFactory<T> channelFactory = null;
try
{
//setup channel
try
{
channelFactory = CreateChannel();
}
catch (InvalidOperationException ex)
{
throw new ApplicationException(string.Format("Invalid endpoint configuration, make sure there is a servicemodel endpoint defined in configuration with the name {0}", EndpointName), ex);
}
channelFactory.Open();
channel = channelFactory.CreateChannel();
object result = methodInfo.Invoke(channel, methodCall.InArgs);
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (FaultException faultException)
{
string msg = "FaultException: " + faultException.Message;
MessageFault fault = faultException.CreateMessageFault();
if (fault.HasDetail)
{
System.Xml.XmlReader reader = fault.GetReaderAtDetailContents();
if (reader.Name == "ExceptionDetail")
{
ExceptionDetail detail = fault.GetDetail<ExceptionDetail>();
msg += "\n\nStack Trace: " + detail.StackTrace;
}
}
return new ReturnMessage(faultException, methodCall);
}
catch (TargetInvocationException targetInvocationException)
{
return targetInvocationException.InnerException != null ? new ReturnMessage(targetInvocationException.InnerException, methodCall) : new ReturnMessage(targetInvocationException, methodCall);
}
catch (Exception exception)
{
return new ReturnMessage(exception, methodCall);
}
finally
{
if (channel as IClientChannel != null)
{
try
{
(channel as IClientChannel).Close(TimeSpan.FromSeconds(5));
}
catch
{
try
{
(channel as IClientChannel).Abort();
}
catch
{
}
}
try
{
(channel as IClientChannel).Dispose();
}
catch
{
}
}
try
{
((IDisposable)channelFactory).Dispose();
}
catch
{
}
}
}
}
public static class ClientProxyFactory
{
public static T CreateProxy<T>() where T : class
{
return CreateProxy<T>(ProxyType.PerCallChannel);
}
public static T CreateProxy<T>(ProxyType proxyType) where T : class
{
return CreateProxy<T>(proxyType, null, null);
}
public static T CreateProxy<T>(ProxyType proxyType, Binding binding, EndpointAddress endpointAddress) where T : class
{
switch (proxyType)
{
case ProxyType.PerCallChannel:
PerCallDisposeRealProxy<T> proxy = null;
proxy = binding == null && endpointAddress == null ? new PerCallDisposeRealProxy<T>() : new PerCallDisposeRealProxy<T>(binding, endpointAddress);
Debug.Assert(proxy != null);
object transparentProxy = proxy.GetTransparentProxy();
Debug.Assert(transparentProxy != null);
Debug.Assert(transparentProxy is T);
return transparentProxy as T;
default:
throw new NotImplementedException("Did not implement proxytype:" + proxyType);
}
}
}
public enum ProxyType
{
/// <summary>
/// PerCall indicates a proxy that will create a channel pr. proxy method call and dispose of it before returning.
/// </summary>
PerCallChannel
}
And call site (in the service agent or whereever you want to call the external service from:
INumeralConverterService proxy = ClientProxyFactory.CreateProxy<INumeralConverterService>();
string result = proxy.DecimalToRoman(i);
Given the ServiceContract (and datacontracts) defined in yet another asssembly, here simply:
[ServiceContract]
public interface INumeralConverterService
{
[OperationContract]
Decimal RomanToDecimal(string roman);
[OperationContract]
string DecimalToRoman(Decimal #decimal);
}