Question

Il y a beaucoup de questions similaires, mais j'ai essayé toutes les solutions dans chacune d'elles en vain.

Nous avons un service Web qui s'initialise avec WebServiceHostFactory, mais si plus de 64 Ko sont lancés, nous obtenons une «400 Bad Request». Normalement, cela serait simplement résolu en augmentant MaxReceivedMessageSize, MaxBufferSize et MaxBufferPoolSize. Le problème est qu'en utilisant WebServiceHostFactory, le Web.Config est complètement ignoré. Aucune modification que je fais dans la section ServiceModel ne se reflète dans le service.

Ce serait bien d'abandonner complètement WebServiceHostFactory et de configurer web.config à partir de zéro, mais notre service ne fonctionnera pas sans lui. L'une des méthodes a un paramètre de flux ainsi que d'autres paramètres de chaîne. Sans l'usine, nous obtenons

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

Ce n'est donc pas une option pour supprimer l'usine. Je ne peux pas comprendre exactement ce que fait l'usine qui corrige cette erreur, mais j'ai passé 4 jours dessus et je ne suis jamais arrivé nulle part.

J'ai également essayé de remplacer MaxReceivedMessageSize par programme, avec quelques exemples que j'ai trouvés partout:

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

Le premier ne fonctionne pas car la fabrique crée un CustomBinding qui ne peut pas être converti en WebHttpBinding. La seconde ne fonctionne pas car il semble que les éléments de liaison sont en lecture seule - peu importe ce sur quoi j'ai défini les éléments, rien ne change, ce que j'ai vérifié en relisant les valeurs après les avoir «modifiées». La troisième était une dernière tentative pour essayer d'y ajouter un nouvel élément de liaison, mais bien sûr, cela a également échoué.

Maintenant, nous sommes complètement perdus. Comment pouvons-nous faire fonctionner cette chose? Vous pensez que ce serait si simple!

Merci les gars

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>

Modifiez, en utilisant une solution suggérée qui n'a pas réussi jusqu'à présent:

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);
        }
    }
Était-ce utile?

La solution

Si vous implémentez votre propre hôte de service personnalisé, vous devriez pouvoir remplacer une méthode appelée "ApplyConfiguration" dans laquelle vous pouvez associer toutes les propriétés de configuration dont vous avez besoin pour votre liaison.Un exemple de code comme indiqué ci-dessous:

EDIT: Ajout de l'implémentation d'usine de mon hôte de service

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

}

Ce qui précède remplace votre configuration de chaque liaison et définit MaxStringContentLength.

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

Maintenant, mon balisage de fichier Service.svc a ceci:

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

Autres conseils

Pour le bénéfice des autres, la réponse ci-dessus va dans le bon sens mais contient de nombreuses erreurs et ne fonctionnera pas sans modifications (par conséquent, l'OP n'a pas pu faire fonctionner la solution). Utilisez ce qui suit et cela fonctionnera pour vous «prêt à l'emploi».

Remarque - Il est extrêmement important de fournir tous les constructeurs ci-dessous et d'utiliser la surcharge de constructeur démontrée en usine, sinon vous obtiendrez le message d'erreur suivant:

InitializeRuntime nécessite que la propriété Description soit initialisée. Soit fournir une ServiceDescription valide dans la méthode CreateDescription, soit remplacer la méthode InitializeRuntime pour fournir une implémentation alternative

Implémentation personnalisée de 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);
        }
    }
}

Implémentation personnalisée de ServiceHostFactory:

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

Le balisage Service1.svc ci-dessus fonctionnera tant que le type est correct. J'ai en fait utilisé cette technique pour remplacer WebServiceHost et autoriser des tailles de réponse JSON plus grandes, mais les principes devraient tous s'appliquer également à ServiceHost.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top