Domanda

Ci sono molte domande simili là fuori, ma ho provato ogni soluzione in ognuna di esse senza risultati.

Abbiamo un servizio Web che inizializza con WebServiceHostFactory, ma se non ci sono più di 64k, otteniamo una "richiesta di cattiva 400". Normalmente, questo verrebbe solo risolto aumentando MaxReceivedMessageSize, MaxBufferSize e MaxBufferPoolSize. Il problema è che utilizzando WebServiceHostFactory, Web.Config viene completamente ignorato. Nessuna modifica che apporto nella sezione Servicemodel riflette nel servizio.

Sarebbe bello abbandonare completamente WebServiceHostFactory e impostare il web.config da zero, ma il nostro servizio non verrà eseguito senza di essa. Uno dei metodi ha un parametro di flusso e altri parametri di stringa. Senza la fabbrica, otteniamo

System.InvalidOperationException: For request in operation Test to be a stream the operation must have a single parameter whose type is Stream

Quindi non è un'opzione per rimuovere la fabbrica. Non riesco a capire esattamente cosa sta facendo la fabbrica che risolve questo errore, ma ci ho trascorso 4 giorni e non sono mai arrivato da nessuna parte.

Ho anche provato a prevalere su MaxReceivedMessageSize in modo programmatico, con alcuni esempi che ho trovato in tutto il luogo:

protected override void OnOpening()
        {
            base.OnOpening();
            foreach (var endpoint in Description.Endpoints)
            {

                //var binding = endpoint.Binding as WebHttpBinding;
                //if (binding != null)
                //{
                //    binding.MaxReceivedMessageSize = 20000000;
                //    binding.MaxBufferSize = 20000000;
                //    binding.MaxBufferPoolSize = 20000000;
                //    binding.ReaderQuotas.MaxArrayLength = 200000000;
                //    binding.ReaderQuotas.MaxStringContentLength = 200000000;
                //    binding.ReaderQuotas.MaxDepth = 32;
                //}


                //var transport = endpoint.Binding.CreateBindingElements().Find<HttpTransportBindingElement>();
                //if (transport != null)
                //{
                //    transport.MaxReceivedMessageSize = 20000000;
                //    transport.MaxBufferPoolSize = 20000000;
                //}


                var newTransport = new HttpTransportBindingElement();
                newTransport.MaxReceivedMessageSize = 20000000;
                newTransport.MaxBufferPoolSize = 20000000;
                endpoint.Binding.CreateBindingElements().Add(newTransport);
            }
        }

Il primo non funziona in quanto la fabbrica crea una bevanda che non può essere lanciata su un webhttpbinding. Il secondo non funziona in quanto sembra che gli elementi vincolanti siano solo letti - non importa a cosa ho impostato gli elementi, nulla cambia, che ho verificato leggendo i valori dopo averli "cambiati". Il terzo è stato un ultimo tentativo di fossare di provare a lanciare un nuovo elemento vincolante lì dentro, ma ovviamente anche questo ha fallito.

Ora siamo completamente in perdita. Come possiamo far funzionare questa cosa? Pensi che sarebbe così semplice!

Grazie ragazzi

Web.config

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
    <compilation targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="rest" maxReceivedMessageSize="500000000" />
      </webHttpBinding>
    </bindings>
    <services>
      <service name="SCAPIService" behaviorConfiguration="ServiceBehaviour">
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="rest" contract="ISCAPIService" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
</configuration>

Modifica, usando una soluzione suggerita che finora non ha avuto successo:

public class MyServiceHost : WebServiceHost
    {
        public MyServiceHost()
        {
        }

        public MyServiceHost(object singletonInstance, params Uri[] baseAddresses)
            : base(singletonInstance, baseAddresses)
        {
        }

        public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }

        protected override void ApplyConfiguration()
        {
            base.ApplyConfiguration();
            APIUsers.TestString += "here" + Description.Endpoints.Count.ToString();
            foreach (var endpoint in this.Description.Endpoints)
            {
                var binding = endpoint.Binding;
                APIUsers.TestString += binding.GetType().ToString();
                if (binding is WebHttpBinding)
                {
                    var web = binding as WebHttpBinding;
                    web.MaxBufferSize = 2000000;
                    web.MaxBufferPoolSize = 2000000;
                    web.MaxReceivedMessageSize = 2000000;
                }
                var myReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
                myReaderQuotas.MaxStringContentLength = 2000000;
                myReaderQuotas.MaxArrayLength = 2000000;
                myReaderQuotas.MaxDepth = 32;
                binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, myReaderQuotas, null);
            }
        }
    }

    class MyWebServiceHostFactory : WebServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new MyServiceHost(serviceType, baseAddresses);
        }
    }
È stato utile?

Soluzione

Se si sta implementando il proprio host di servizio personalizzato, dovresti essere in grado di sovrascrivere un metodo chiamato "ApplicaConfiguration" in cui è possibile associare tutte le proprietà di configurazione necessarie per il tuo rilegatura. Qualche codice di esempio come mostrato di seguito:

EDIT: Aggiunta di My ServiceHost Factory Implementation

public class MyServiceHost : System.ServiceModel.ServiceHost
{
    public MyServiceHost () { }

    public MyServiceHost (Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses)
    {

    }

    public MyServiceHost (object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
    {

    }

protected override void ApplyConfiguration()
            {
                Console.WriteLine("ApplyConfiguration (thread {0})", System.Threading.Thread.CurrentThread.ManagedThreadId);
                base.ApplyConfiguration();
                foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
                {
                    Binding binding = endpoint.Binding;
                    var binding = endpoint.Binding;
                    if(binding is WebHttpBinding)
                    {
                        var web = binding as WebHttpBinding;
                        web.MaxBufferSize = 2000000;
                        web.MaxReceivedMessageSize = 2000000;
                    }
                    var myReaderQuotas = new XmlDictionaryReaderQuotas();
                    myReaderQuotas.MaxStringContentLength = 5242880;
                    binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, myReaderQuotas, null); 
                }
            }

}

Quanto sopra sovrascrive la configurazione di ciascun legame e imposta la lunghezza MAXStringContent.

public sealed class MyServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory
    {
        public override System.ServiceModel.ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
        {
            return base.CreateServiceHost(constructorString, baseAddresses);
        }

        protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new MyServiceHost(serviceType, baseAddresses);
        }
    }

Ora il mio markup del file Service.svc ha questo:

<%@ ServiceHost Language="C#" Debug="true" Factory="Sample.MyServiceHostFactory" Service="Sample.ReaderQuotasService" CodeBehind="ReaderQuotasService.svc.cs" %>

Altri suggerimenti

A beneficio degli altri, la risposta di cui sopra percorre la strada giusta ma ha molti errori e non funzionerà senza modifiche (quindi l'OP non è riuscito a far funzionare la soluzione). Usa quanto segue e funzionerà per te "fuori dalla scatola".

Nota - È estremamente Importante per fornire tutti i costruttori di seguito e utilizzare il sovraccarico del costruttore dimostrato in fabbrica, altrimenti otterrai il seguente messaggio di errore:

Initializeruntime richiede che la proprietà Descrizione sia inizializzata. Fornire una manutenzione valida nel metodo createdescription o sovrascrivere il metodo inizializerime per fornire un'implementazione alternativa

Implementazione personalizzata di ServiceHost:

public class CustomServiceHost : ServiceHost
{
    public CustomServiceHost()
    {
    }

    public CustomServiceHost(object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
    {
    }

    public CustomServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses)
    {
    }

    protected override void  OnOpening()
    {
        base.OnOpening();

        foreach (var endpoint in this.Description.Endpoints)
        {
            var binding = endpoint.Binding;
            var web = binding as WebHttpBinding;

            if (web != null)
            {
                web.MaxBufferSize = 2147483647;
                web.MaxReceivedMessageSize = 2147483647;
            }

            var myReaderQuotas = new XmlDictionaryReaderQuotas { MaxStringContentLength = 2147483647 };

            binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, myReaderQuotas, null);
        }
    }
}

Custom ServiceHostFactory Implementation:

public sealed class CustomServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new CustomServiceHost(serviceType, baseAddresses);
    }
}

Il markup Service1.SVC sopra funzionerà fintanto che il tipo è corretto. In realtà ho usato questa tecnica per sovrascrivere WebServiceHost e consentire dimensioni di risposta JSON più grandi, ma i principi dovrebbero essere applicati anche a ServiceHost.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top