简体   繁体   中英

WCF authentication with Azure ACS increase MaxReceivedMessageSize

I have a WCF service that authenticates via Azure ACS , it works beautifully except that when I upload large files to it, I get "(413) Request Entity Too Large"

So clearly I need to increase MaxReceivedMessageSize , however, my binding type isn't a WSHttpBinding but a IssuedTokenWSTrustBinding so doesn't expose this property and I guess I don't fully understand how the HTTP bindings are created in the code below. Is it possible to configure MaxReceivedMessageSize on my bindings somehow?

    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        string acsUsernameEndpoint = String.Format("https://{0}.{1}/v2/wstrust/13/username", ACSServiceNamespace, AcsHostUrl);
        ServiceHost rpHost = new ServiceHost(typeof(DataTransferService));
        rpHost.Credentials.ServiceCertificate.Certificate = GetServiceCertificateWithPrivateKey();
        rpHost.AddServiceEndpoint(typeof(IUploadService),
                                   Bindings.CreateServiceBinding(acsUsernameEndpoint),
                                   new Uri(ServiceAddress));

        // Windows Identity Foundation token handlers can pick up the relevant settings.
        ServiceConfiguration serviceConfiguration = new ServiceConfiguration();
        // FederatedServiceCredentials.ConfigureServiceHost etc...
        return rpHost;
    }

    public static class Bindings
    {
        public static Binding CreateServiceBinding(string acsUsernameEndpoint)
        {
            return new IssuedTokenWSTrustBinding(CreateAcsUsernameBinding(), new EndpointAddress(acsUsernameEndpoint));
        }

        public static Binding CreateAcsUsernameBinding()
        {
            return new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential);
        }
    }

Solved! As I'm not explicitly defining my endpoints it should be possible to set ReaderQuotas and MaxReceivedMessageSize etc on the 'default' endpoints with .Net 4+ by not naming them, this didn't work.

In the end I managed to change the ReaderQuotas and MaxReceivedMessageSize on the binding by creating a new Binding class that overrides CreateBindingElements() , this new class takes the binding by the IssuedTokenWSTrustBinding and calls its CreateBindingElements() to create a clone of its binding components, this then allows me to tweak the settings. I'm left with a completely code-based WCF configuration, not sure I like the .clone() - there might be a more eloquent solution.

private class LargeTransportBinding : Binding
{
    Binding originalBinding;

    public LargeTransportBinding(Binding sourceBinding)
    {
        originalBinding = sourceBinding;
    }

    public override BindingElementCollection CreateBindingElements()
    {
        // Copy
        BindingElementCollection modifiedBindingElementCollection = originalBinding.CreateBindingElements().Clone();

        // Tweak Reader Quoters and max buffer sizes
        TextMessageEncodingBindingElement encoding = (TextMessageEncodingBindingElement)modifiedBindingElementCollection[1];
        encoding.ReaderQuotas.MaxArrayLength = int.MaxValue;
        encoding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
        encoding.ReaderQuotas.MaxStringContentLength = int.MaxValue;

        HttpTransportBindingElement transport = (HttpTransportBindingElement)modifiedBindingElementCollection[2];
        transport.MaxBufferPoolSize = int.MaxValue;
        transport.MaxBufferSize = int.MaxValue;
        transport.MaxReceivedMessageSize = int.MaxValue;

        return modifiedBindingElementCollection;
    }

    public override string Scheme
    {
        get { return originalBinding.Scheme; }
    }
}

and calling it as follows:

    var binding =  Bindings.CreateServiceBinding(acsUsernameEndpoint);
    rpHost.AddServiceEndpoint(typeof(IUploadService),
                     new LargeTransportBinding(binding),
                     new Uri(ServiceAddress));

Remembering to reduce the Int.MaxValue to something more realistic to reduce the chance of a DoS attack. I hope this saves somebody the many days I had to spend trawling the internet to solve this.

For IIS 7, this is also required in the web.config:

  <system.web>
    <httpRuntime maxRequestLength="10240" />
  </system.web>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM