How to set the MaxReceivedMessageSize programmatically when using a WCF Client? - wcf

I want to set the MaxReceivedMessageSize property to some higher limit (Due to (400) Bad Request error) in my client programmatically.
This is the code I am using...
WCFServiceTestClient wcfClient =
new WCFServiceTestClient(new wsHttpBinding(), strServiceURL);
My service url is dynamic and hence cannot use the web.config.
//The following code doesn't seem to take effect
((WSHttpBinding)wcfClient.ChannelFactory.Endpoint.Binding)
.MaxReceivedMessageSize = 2147483647;
What am I doing wrong?

Have you tried re-ordering the calls so that you set the MaxReceivedMessageSize before instantiating the client? eg,
var binding = new wsHttpBinding();
binding.MaxReceivedMessageSize = Int32.MaxValue;
var wcfClient = new WCFServiceTestClient(binding, strServiceURL);
This may or may not help your 400 error, though.

I had similar problems in my wcf-service and I solved it with:
CustomBinding binding = (CustomBinding)PDAServiceContractClient.CreateDefaultBinding();
HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
httpBindingElement.MaxBufferSize = Int32.MaxValue;
httpBindingElement.MaxReceivedMessageSize = Int32.MaxValue;
binding.Elements.Add(httpBindingElement);
string address = PDAServiceContractClient.EndpointAddress.Uri.ToString();
m_proxy = new PDAServiceContractClient(binding, new EndpointAddress(address));

This works well, though it's not that obvious. It retains all the existing binding properties and only adjusts the MaxReceivedMessageSize (which, incidentally, also increases MaxBufferSize to the same size).
Dim oClient as WcfClient = New WcfClient
CType(oClient.Endpoint.Binding, ServiceModel.BasicHttpBinding).MaxReceivedMessageSize = Int32.MaxValue

Related

Content issue in .NET Core app Consuming a WCF service

I am trying to call a WCF service method from an .NET Core Web API using the new Visual Studio WCF Connected service.
But when I am testing this, I get the following error:-
The content type multipart/related; type="application/xop+xml"; start="http://tempuri.org/0"; boundary="uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a+id=1197"; start-info="text/xml" of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of the response were: '
--uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a+id=1197
Content-ID: http://tempuri.org/0
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
The exposed WCF service uses MTOM MessageEncoding and in traditional .NET framework client application, we can set the client to use MTOM in the application's config file but in .NET core, we don't have the config file where we can set the MessageEncoding and all this configuration
is taken care of in the code present in Reference.cs(which is a generated file).
I thinking changing this generated file to set the MessageEncoding is not a good option.
Any idea on what is the best way to handle this issue?
I just came to know from WCF Core team that currently MTOM encoding is not supported in .NET Core based clients. This is a requested feature which will be available in future versions.
Here is github link which has more information: Adding MTOM support in WCF runtime
I was facing the same MTOM consumtion issue in my project, and had to find a way to be able to consume the service.
It ended up in some (ugly) code, but functional.
I just wanted to share the solution (as I wasn't able to find anything on the web) :
To start, generate the Client with Visual Studio (2017 in my case) by adding a connected service (as you would do for a regular SOAP client).
This will help you save lot a dummy code typing ;)
then, use RestSharp to call the endpoint, and serialize manually the response/request :
var client = new RestClient("http://myService/Service");
var request = new RestRequest(Method.POST);
request.AddHeader("accept", "text/plain");
request.AddHeader("content-type", "text/xml");
// create parameter
var serializer = new XmlSerializer(typeof(myParameter));
var requestParameter = new myParameter(1,2,3,4);
string requestParameterStr;
var namepsaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true, NamespaceHandling = NamespaceHandling.OmitDuplicates }; // some parameters to make it clean, only OmitXmlDeclaration is mandatory
using (var stringWriter = new StringWriter())
{
using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
{
serializer.Serialize(xmlWriter, requestParameter, namepsaces);
requestParameterStr = stringWriter.ToString();
}
}
// patch parameter to add the namespace prefix required by consumer service
requestParameterStr = requestParameterStr.Replace("myParameter", "myNs:myParameter");
// wrap parameter in a soap envelop
requestParameterStr =
$"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:myNs=\"http://myService/Service/\"><soapenv:Header/><soapenv:Body>{requestParameterStr}</soapenv:Body></soapenv:Envelope>";
request.AddParameter(
"text/xml",
requestParameterStr,
ParameterType.RequestBody);
var response = client.Execute(request);
var mtomMsg = response.Content;
// remove MTOM elements from the received Content. here comes the ugly part ^^
var responseContentType = response.ContentType;
var contentTypeElements = responseContentType.Split(";");
var boundary = contentTypeElements.FirstOrDefault(x => x.TrimStart().StartsWith("boundary="))?.Trim().Substring("boundary=".Length);
var startElement = contentTypeElements.FirstOrDefault(x => x.TrimStart().StartsWith("start="))?.Trim().Substring("start=".Length);
boundary = boundary.Trim('"');
startElement = startElement.Trim('"');
var startIndex = mtomMsg.IndexOf(startElement) + startElement.Length;
var endIndex = mtomMsg.LastIndexOf("--" + boundary + "--", startIndex);
var cleanedMtomMsg = mtomMsg.Substring(startIndex, endIndex - startIndex);
// Get the result inside the Soap envelop
var soapDocument = XDocument.Parse(cleanedMtomMsg);
var envelopeElt = soapDocument.Root;
var bodyElt = (System.Xml.Linq.XElement)envelopeElt.FirstNode;
var responseStr = bodyElt.FirstNode.ToString();
// deserialize the result
var memstream = new MemoryStream(Encoding.UTF8.GetBytes(responseStr));
var reader = XmlDictionaryReader.CreateTextReader(memstream, XmlDictionaryReaderQuotas.Max);
var deserializer = new XmlSerializer(typeof(myResponse), "http://myService/Service/"); // don't forget the namespace
var result = deserializer.Deserialize(reader) as myResponse;
note : myParameter & myResponse are the classes generated at step 1
There could be easier ways, but at least, this works.
Hope some of you find this helpfull.
In my case, I solved this issue by using WcfCoreMtomEncoder package in my .NET Core 2.1 project. You can learn more about using it here
I fixed the problem by installing latest version of visual studio 2017. by installing latest version of visual studio it will automatically update your net core to the latest verion (1.1.2).
you can also use "binaryMessageEncodingBindingElement":
ChannelFactory<ITestService> factory = null;
ITestService serviceProxy = null;
BinaryMessageEncodingBindingElement binaryMessageEncodingBindingElement = new BinaryMessageEncodingBindingElement();
binaryMessageEncodingBindingElement.CompressionFormat = CompressionFormat.GZip;
HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
httpTransportBindingElement.MaxReceivedMessageSize = int.MaxValue;
CustomBinding customBinding = new CustomBinding(new BindingElement[] { binaryMessageEncodingBindingElement, httpTransportBindingElement });
factory = new ChannelFactory<ITestService>(customBinding, new EndpointAddress("http://localhost/test.svc/mex"));
serviceProxy = factory.CreateChannel();
var result = serviceProxy.GetResultData(50);

How to set the leaseTimeout setting programmaticaly?

We have a WCF service (NetTcpBinding) that sits behind a load balancer. I've read that in order to avoid "stickyniss" I have lower the LeaseTime the channels get in the channel pool.
I've only found samples how to set this value using the config file, but I would like to set it programmaticaly, any pointers?
You can access the LeaseTimeout property via the TcpTransportBindingElement, through the ConnectionPoolSettings property:
TcpTransportBindingElement tcpBE = new TcpTransportBindingElement();
tcpBE.ConnectionPoolSettings.LeaseTimeout = TimeSpan.FromSeconds(1);
If you have a NetTcpBinding object, you'll need to first convert it into a CustomBinding, then access the binding element. The example below shows one way of doing this.
NetTcpBinding myOriginalBinding = CreateBinding();
CustomBinding newBinding = new CustomBinding(myOriginalBinding);
TcpTransportBindingElement tcpBE = newBinding.Elements.Find<TcpTransportBindingElement>();
tcpBE.ConnectionPoolSettings.LeaseTimeout = TimeSpan.FromSeconds(1);

Modify SOAP header Mustunderstand attribute in WCF client

I am writing a WCF client for a service (not WCF). Getting an error that Unprocessed 'mustUnderstand' header element: {http://www.w3.org/2005/08/addressing}Action, because request SOAP contains header with mustunderstand='true'. I have to either set it false or remove the whole header. can you show the way to do that?
Here is the binding code
var transportElement = new HttpsTransportBindingElement();
transportElement.AuthenticationScheme = AuthenticationSchemes.Basic;
var messegeElement = new TextMessageEncodingBindingElement();
messegeElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap11);
var binding = new CustomBinding(messegeElement, transportElement);
return binding;
I resolved this one by setting AddressingVersion to None that did not put the SOAP headers.
here is the code
MessageVersion.CreateVersion(EnvelopeVersion.Soap11, AddressingVersion.None)
Specifying the messageVersion solved my problem.
<mtomMessageEncoding messageVersion="Soap12"/>

How can I set the maxItemsInObjectGraph property programmatically from a Silverlight Application?

I have a Silverlight 3.0 application that is using a WCF service to communicate with the database, and when I have large amounts of data being returned from the service methods I get Service Not Found errors. I am fairly confident that the solution to it is to simply update the maxItemsInObjectGraph property, but I am creating the service client progrogrammatically and cannot find where to set this property. Here is what I am doing right now:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
MaxReceivedMessageSize = int.MaxValue,
MaxBufferSize = int.MaxValue
};
MyService.MyServiceServiceClient client = new MyService.MyServiceProxyServiceClient(binding, new EndpointAddress(new Uri(Application.Current.Host.Source, "../MyService.svc")));
It's not defined in binding, but in Service Behavior.
In Silveright, maxItemsInObjectGraph defaults to int.MaxValue.
Here is an article on how to change it for .NET application, but not Silverlight: Programattically setting the MaxItemsInObjectGraph property in client
A snippet of the code:
protected ISecurityAdministrationService GetSecAdminClient()
{
ChannelFactory<ISecurityAdministrationService> factory = new ChannelFactory<ISecurityAdministrationService>(wsSecAdminBinding, SecAdminEndpointAddress);
foreach (OperationDescription op in factory.Endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior =op.Behaviors.Find<DataContractSerializerOperationBehavior>() as DataContractSerializerOperationBehavior;
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = 2147483647;
}
}
ISecurityAdministrationService client = factory.CreateChannel();
return client;
}
The following is a function that I've used inside a client object that inherits from
System.ServiceModel.ClientBase(Of IServiceName)
The purpose of the method is to programatically set the MaxItemsInObjectGraph value for each operation. This allows me to have much more complex structures.
Private Sub IncreaseObjectCount()
For Each op As System.ServiceModel.Description.OperationDescription In Me.Endpoint.Contract.Operations
For Each dscob As System.ServiceModel.Description.DataContractSerializerOperationBehavior In op.Behaviors.FindAll(Of System.ServiceModel.Description.DataContractSerializerOperationBehavior)()
dcsob.MaxItemsInObjectGraph = Integer.MaxValue
Next dcsob
Next op
End Sub
I usually call it in the constructors of the object.
Change the maxItemsInObjectGraph in your WCF service for each endpoint, changing it in Silverlight means the client will be able to support the behavior, but the service must support it aswell.
After changing it in your service, regenerate the proxy/update web service, and you will get a new ServiceReference.config, that will include the new maxItemsInObjectGraph value

WCF endpoint binding settings don't get updated

All attempts to change configuration settings of WCF self hosted service endpoint fail:
public void Start()
{
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = "NAVBinding";
//--------------------START editing-------------------------------
TimeSpan interval = new TimeSpan(1, 50, 00); // all these following (inbetween comments) lines have no effect
binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.ReceiveTimeout = interval;
binding.OpenTimeout = interval;
binding.CloseTimeout = interval;
binding.SendTimeout = interval;
XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
readerQuotas.MaxDepth = 2147483647;
readerQuotas.MaxStringContentLength = 2147483647;
readerQuotas.MaxArrayLength = 2147483647;
readerQuotas.MaxBytesPerRead = 2147483647;
readerQuotas.MaxNameTableCharCount = 2147483647;
binding.ReaderQuotas = readerQuotas;
//----------------------END editing---------------------------
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
Uri baseAddress = new Uri("http://localhost:8000/nav/customer");
Customer_Service service = new Customer_Service();
serviceHost = new ServiceHost(service, baseAddress);
serviceHost.AddServiceEndpoint(typeof(ICustomer_Service), binding, baseAddress);
OpenMetadataExchange(baseAddress);
service.navEventListner = this;
serviceHost.Open();
}
but I can easily change the MaxReceivedMessageSize property with the help of wcfStorm application and in this case it really is changed. But after restarting service, everything gets back to its default settings (for example MaxReceivedMessageSize = 65536).
Please, what am I doing whrong? How to edit my code in order new values get updated?
Setting those values on the SERVER SIDE does not automagically set them on the CLIENT SIDE.
Only setting them on the server side is not enough - the transfer between client and server is dictated by the smallest of the two settings between client and server. Even if the server allows 2 GB of message size, if the client still insists on 64 KB, the smaller value of 64 KB wins. That doesn't mean the 2 GB setting on the server side isn't there - it is, but it's not being effective because the client uses a smaller setting.
If you want to use the same settings on the client side, you will need to configure the client side accordingly. You will need to do the same thing when creating your client proxy, or configure your client from an app.config file.