C# WCF Web Api 4 MaxReceivedMessageSize - c#

I am using the WCF Web Api 4.0 framework and am running into the maxReceivedMessageSize has exceeded 65,000 error.
I've updated my webconfig to look like this but because I am uisng the WCF Web Api I think this isn't even used anymore as I am no longer using a webHttpEndpoint?
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name=""
helpEnabled="true"
automaticFormatSelectionEnabled="true"
maxReceivedMessageSize="4194304" />
</webHttpEndpoint>
Where do I specify MaxReceivedMessageSize in the new WCF Web Api?
I've also tried a CustomHttpOperationHandlerFactory to no avail:
public class CustomHttpOperationHandlerFactory: HttpOperationHandlerFactory
{
protected override System.Collections.ObjectModel.Collection<HttpOperationHandler> OnCreateRequestHandlers(System.ServiceModel.Description.ServiceEndpoint endpoint, HttpOperationDescription operation)
{
var binding = (HttpBinding)endpoint.Binding;
binding.MaxReceivedMessageSize = Int32.MaxValue;
return base.OnCreateRequestHandlers(endpoint, operation);
}
}

the maxReceivedMessageSize is a property you have to define on the binding you´re using. WCF in .Net 4 introduced the simplified configuration, so if you don´t configure anything, default values will be used.
The example below is valid for the wshttpBinding, you have the ammend it according to your used binding and register it in your web.config (assuming you´re using an IIS hosted service) in the servicemodel-binding section.
<wsHttpBinding>
<binding name="CalculatorBinding" maxBufferPoolSize="2000000" maxReceivedMessageSize="2000000000" >
<security mode="Transport" >
<transport clientCredentialType="Windows" />
</security>
<readerQuotas maxDepth="2000000" maxStringContentLength="2000000"
maxArrayLength="2000000"
maxBytesPerRead="2000000"
maxNameTableCharCount="2000000" />
</binding>
</wsHttpBinding>
HTH
Dominik

If you're trying to do this programatically (via using MapServiceRoute with HttpHostConfiguration.Create) the way you do it is like this:
IHttpHostConfigurationBuilder httpHostConfiguration = HttpHostConfiguration.Create(); //And add on whatever configuration details you would normally have
RouteTable.Routes.MapServiceRoute<MyService, NoMessageSizeLimitHostConfig>(serviceUri, httpHostConfiguration);
The NoMessageSizeLimitHostConfig is an extension of HttpConfigurableServiceHostFactory that looks something like:
public class NoMessageSizeLimitHostConfig : HttpConfigurableServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = base.CreateServiceHost(serviceType, baseAddresses);
foreach (var endpoint in host.Description.Endpoints)
{
var binding = endpoint.Binding as HttpBinding;
if (binding != null)
{
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.TransferMode = TransferMode.Streamed;
}
}
return host;
}
}

If you are hosting in IIS, you can set the values where ever you define the route (in my case, the global.asax). If you have TransferMode set to buffered (the default), you will also need to set MaxBufferSize to the same value as MaxReceivedMessageSize.
protected void Application_Start()
{
var config = new HttpConfiguration();
config.MaxReceivedMessageSize = int.MaxValue;
config.MaxBufferSize = int.MaxValue;
RouteTable.Routes.MapServiceRoute<MyService>("api", config);
}

This is how you can do it in code
var endpoint = ((HttpEndpoint)host.Description.Endpoints[0]); //Assuming one endpoint
endpoint.TransferMode = TransferMode.Streamed;
endpoint.MaxReceivedMessageSize = 1024 * 1024 * 10; // Allow files up to 10MB
If you create a your own custom host, derived from the standard one, there is a method that you can overload to configure the HttpEndpoint.

Related

Status code 413 (RequestEntityTooLarge) / Status code 415 (UnsupportedMediaType). WCF Programmatically

I am calling a WCF web service programmatically by generating class files through SvcUtil.exe.
All working fine but when I try to send an image (literally a file with size more than 200KB), I get this error.
I know I need to increase maxReceivedMessageSize and maxBufferPoolSize to the maximum to send large files to the WCF service. Hence, the XML version of doing this will be like below:
<binding name="SampleBinding" allowCookies="true" messageEncoding="Mtom" maxReceivedMessageSize="20000000" maxBufferSize="20000000" maxBufferPoolSize="20000000">
<readerQuotas maxDepth="32" maxArrayLength="200000000" maxStringContentLength="200000000"/>
<security mode="None">
<transport proxyCredentialType="Basic"/>
</security>
</binding>
In this app, since I am using class files generated by SvcUtil, I need to call my WCF service method programmatically.
So I did,
var binding = new BasicHttpBinding();
binding.MaxReceivedMessageSize = binding.MaxBufferPoolSize = long.MaxValue;
binding.AllowCookies = true;
binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
binding.ReaderQuotas.MaxArrayLength = binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = binding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
binding.ReaderQuotas.MaxDepth = int.MaxValue;
webAPI = new WebAPIClient(binding, new EndpointAddress(soapUrl));
The XML version works really well but the C# version failed with below stack trace:
There was an error on processing web request: Status code
413(RequestEntityTooLarge): Request Entity Too Large
EDIT
I have been approached to use custom binding. Below is my custom binding code:
CustomBinding binding = new CustomBinding()
{
Name = "SampleBinding",
ReceiveTimeout = new TimeSpan(0, 0, 10, 0, 0),
SendTimeout = new TimeSpan(0, 0, 10, 0, 0),
};
var element1 = new TextMessageEncodingBindingElement()
{
ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxDepth = 2147483647,
MaxStringContentLength = 2147483647,
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxNameTableCharCount = 2147483647
}
};
var element2 = new HttpTransportBindingElement()
{
ManualAddressing = false,
MaxReceivedMessageSize = 2147483647,
AllowCookies = false,
AuthenticationScheme = System.Net.AuthenticationSchemes.None,
BypassProxyOnLocal = false,
MaxBufferSize = 2147483647,
ProxyAuthenticationScheme = System.Net.AuthenticationSchemes.None,
TransferMode = TransferMode.Buffered,
UseDefaultWebProxy = true
};
var element3 = new TextMessageEncodingBindingElement(MessageVersion.Soap12WSAddressing10, System.Text.Encoding.UTF8);
binding.Elements.Add(element1);
binding.Elements.Add(element2);
binding.Elements.Add(element3);
webAPI = new WebAPIClient(binding, new EndpointAddress(soapUrl));
There was an error on processing web request: Status code
415(UnsupportedMediaType): Cannot process the message because the
content type 'application/soap+xml; charset=utf-8' was not the
expected type 'text/xml; charset=utf-8'.
I don't know what's wrong. May you help me?
I just found an answer and posting the same here for future users who might have the same issue as me:
My client call
webAPI = new WebAPIClient(new BasicHttpBinding(), new EndpointAddress(_urlString);
Server Configuration for the WCF Service
<endpoint address="url/WebAPI.svc" binding="basicHttpBinding" contract="MyContract.IWebAPI" />
<bindings>
<basicHttpBinding>
<binding maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
As you can see I did not mention any name for the binding configuration here and it just worked like a charm.
Answer inspired from this SO answer

How to read System.serviceModel in Class Library with Proxy implementation of WCF service

I am trying to read service configuration in Class Library from the app.config file of the library. but getting below exception
Could not find endpoint element with name 'WSHttpBinding_IUsers' and contract 'ISGP.Plugins.SolveService.IUsers'
in the ServiceModel client configuration section.
This might be because no configuration file was found for your application,
or because no endpoint element matching this name could be found in the client element.
I tried ti implement the below code to read the config and create the client
public class ServiceManager
{
public static T CreateServiceClient<T>(string configName)
{
// string _assemblyLocation = Assembly.GetExecutingAssembly().Location;
var configuration = ConfigurationManager.OpenMappedExeConfiguration(
new ExeConfigurationFileMap
{
ExeConfigFilename = "app.config"
}, ConfigurationUserLevel.None);
ConfigurationChannelFactory<T> channelFactory = new ConfigurationChannelFactory<T>(configName, configuration, null);
var client = channelFactory.CreateChannel();
return client;
}
}
Call this method as below
usersClient= (UsersClient)ServiceManager.CreateServiceClient<IUsersChannel>("WSHttpBinding_IUsers");
usersClient.ClientCredentials.UserName.UserName = userName;
usersClient.ClientCredentials.UserName.Password = password;
But it throws the above exception the app.config file is as below
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IUsers">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://xxxxxx16.prod.xxxxx.local/WebServices/v3/Users.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IUsers"
contract="ISGP.Plugins.SolveService.IUsers" name="WSHttpBinding_IUsers" />
</client>
</system.serviceModel>
Please pass the endpoint parameter in the channel factory constructor.
ConfigurationChannelFactory channelFactory = new
ConfigurationChannelFactory(configName, configuration, null);
You can refer to the following code.
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "app.config";
Configuration newConfiguration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
ConfigurationChannelFactory<IService> factory = new ConfigurationChannelFactory<IService>("endpoint1", newConfiguration, new EndpointAddress("http://localhost:8000/servicemodelsamples/service"));
factory.Credentials.UserName.UserName = "jack";
factory.Credentials.UserName.Password = "123456";
IService client1 = factory.CreateChannel();
https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/configuration-channel-factory
Feel free to let me know if there is anything I can help with.

WCF - Setting Policy for UsernameToken

I received an updated WSDL for a service I'm consuming which has below Policy added
<wsp:Policy wssutil:Id="UsernameToken">
<ns0:SupportingTokens xmlns:ns0="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512">
<wsp:Policy>
<ns0:UsernameToken ns0:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns0:WssUsernameToken10 />
</wsp:Policy>
</ns0:UsernameToken>
</wsp:Policy>
</ns0:SupportingTokens>
</wsp:Policy>
I have updated my reference by right clicking the Service Reference --> Configure Service option inside Visual Studio. This generated a customBinding replacing my previous basicHttpBinding
<customBinding>
<binding name="myBindingName">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'http://ouaf.oracle.com/webservices/cm/CM-CustConnAcctDetailExtract': -->
<!-- <wsdl:binding name='CM-CustConnAcctDetailExtractSoapBinding'> -->
<!-- <ns0:SupportingTokens xmlns:ns0="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512">..</ns0:SupportingTokens> -->
<textMessageEncoding messageVersion="Soap11" />
<httpTransport />
</binding>
</customBinding>
Do I need to use this customBinding only? Or is there any option in basicBinding that makes it work?
If I use my basicBinding with TransportWithMessageCredential, I get below error:
The provided URI is Invalid; HTTPS is expected
I ran this using SoapUI. In addition to UserName and Passwrod, I had to supply WSS-PasswordType as PasswordText. Without supplying this parameter, I get an error in SoapUI
Error on verifying message against security policy Error code:1000
I'm not sure how to supply WSS-PasswordType in my basicHttpBinding.
My basicHttpBinding is as below
protected BasicHttpBinding GetBinding()
{
return new BasicHttpBinding()
{
Name = "BasicHttpBinding",
ReceiveTimeout = new TimeSpan(0, 0, 2, 0),
SendTimeout = new TimeSpan(0, 0, 2, 0),
Security =
{
Mode = BasicHttpSecurityMode.TransportCredentialOnly,
Transport =
{
ClientCredentialType = HttpClientCredentialType.Basic,
ProxyCredentialType = HttpProxyCredentialType.None,
Realm = ""
},
Message =
{
ClientCredentialType = BasicHttpMessageCredentialType.UserName,
AlgorithmSuite = SecurityAlgorithmSuite.Default
}
},
MaxBufferSize = Int32.MaxValue,
MaxReceivedMessageSize = Int32.MaxValue,
ReaderQuotas = new XmlDictionaryReaderQuotas()
{
MaxBytesPerRead = 8192
}
};
}
I'm able to work this through by changing my binding to Custom Binding
protected CustomBinding GetCustomBinding()
{
var customBinding = new CustomBinding() { Name = "CustomBinding" };
customBinding.Elements.Add(new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap11 });
var securityBindingElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityBindingElement.AllowInsecureTransport = true;
securityBindingElement.EnableUnsecuredResponse = true;
securityBindingElement.IncludeTimestamp = false;
customBinding.Elements.Add(securityBindingElement);
customBinding.Elements.Add(new HttpTransportBindingElement());
return customBinding;
}

WCF Session Id changes with each call

I am trying to track and use a session id between calls to a WCF service however after each call by the same WCF client instance I receive two different session ids.
Here is the service contract, specifying that sessions are required:
[ServiceContract(SessionMode=SessionMode.Required)]
public interface IMonkeyService
{
[OperationContract(ProtectionLevel=System.Net.Security.ProtectionLevel.None, IsOneWay = true, IsInitiating = true, IsTerminating = false)]
void Init();
[OperationContract(ProtectionLevel = System.Net.Security.ProtectionLevel.None, IsOneWay = false, IsInitiating = false, IsTerminating = false)]
string WhereAreMyMonkies();
[OperationContract(ProtectionLevel = System.Net.Security.ProtectionLevel.None, IsOneWay = true, IsInitiating = false, IsTerminating = true)]
void End();
}
Here is the service implementation:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, IncludeExceptionDetailInFaults=true)]
public class BestMonkeyService : IMonkeyService
{
public void Init() { ;}
public void End() { ;}
public string WhereAreMyMonkies()
{
return "Right here";
}
}
Here is the service being opened:
_Service = new ServiceHost(typeof(BestMonkeyService));
var binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
binding.ReliableSession.Enabled = true;
string uriAddress = "http://localhost:8000/MONKEY_SERVICE";
var endpoint = _Service.AddServiceEndpoint(typeof(IMonkeyService), binding, uriAddress);
_Service.Open();
Here is the client configuration
<system.serviceModel>
<client>
<endpoint address="http://localhost:8000/MONKEY_SERVICE" bindingConfiguration="wsHttpBindingConfiguration"
binding="wsHttpBinding" contract="IMonkeyService" />
</client>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBindingConfiguration">
<security mode="None" />
<reliableSession enabled="true" />
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
The call by the client which is kept open after the first call:
var client = new MonkeyClient();
client.Init();
client.WhereAreMyMonkies();
client.WhereAreMyMonkies();
client.End();
I am getting an ActionNotSupportedException
The message with Action 'http://tempuri.org/IMonkeyService/WhereAreMyMonkies' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
I have both service and client configured using the same binding and security. What am I missing?
As explained here, because the default value of IsInitiating parameter is true each of your calls started a new session.
You need something like this:
[OperationContract(IsInitiating=false, IsTerminating=false)]
string WhereAreMyMonkies();
By default a session is initiated when channel is opened. You can also add methods that explicitly create and terminate a session (as explained in the documentation).
WSHttpBinding doesn't support sessions without reliable messaging or security sessions.
See the answer to How to enable Session with SSL wsHttpBinding in WCF

Programmatically build a WCF Binding in Silverlight

I have a Binding that is configured as such in my .clientconfig file.
<customBinding>
<binding name="CustomBinding_MyService">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
I need to build this same binding programmatically (its a long story, I just do). My question is, how do I do this in C#? Currently, I have
CustomBinding binding = new CustomBinding();
However, I'm not sure where to go from there. Thanks!
It'll look something like this:
var customBinding = new CustomBinding(
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()
{
MaxReceivedMessageSize = 2147483647,
MaxBufferSize = 2147483647
}
);
var endpoint = new EndpointAddress("http://www.myservice.com/myservice.svc");
var myServiceClient = new MyServiceClient(customBinding, endpoint);
myServiceClient.SayHelloAsync(); // Or whatever
hopefully this helps: Runtime data binding

Categories

Resources