【问题标题】:adding GZIP to WCF REST service in C#在 C# 中将 GZIP 添加到 WCF REST 服务
【发布时间】:2012-10-02 11:03:02
【问题描述】:

我在 C#.NET WCF Web 服务上启用 GZIP 压缩时遇到问题,希望有人知道我在 App.conf 配置文件中缺少什么,或者在调用启动代码中的 web 服务。

我点击了链接 Applying GZIP Compression to WCF Services,该链接指向下载 Microsoft 添加 GZIP 的示例,但该示例与我设置 Web 服务的方式无关。

所以我的 App.conf 看起来像

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="MyService.Service1">
        <endpoint address="http://localhost:8080/webservice" binding="webHttpBinding" contract="MyServiceContract.IService"/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior>
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <extensions>
      <bindingElementExtensions>
        <add name="gzipMessageEncoding" type="MyServiceHost.GZipMessageEncodingElement, MyServiceHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </bindingElementExtensions>
    </extensions>
    <protocolMapping>
      <add scheme="http" binding="customBinding" />
    </protocolMapping>
    <bindings>
      <customBinding>
        <binding>
          <gzipMessageEncoding innerMessageEncoding="textMessageEncoding"/>
          <httpTransport hostNameComparisonMode="StrongWildcard" manualAddressing="False" maxReceivedMessageSize="65536" authenticationScheme="Anonymous" bypassProxyOnLocal="False" realm="" useDefaultWebProxy="True"/>
        </binding>
      </customBinding>
    </bindings>
  </system.serviceModel>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

我只是将 MS 示例中的配置和 GZIP 类复制到我的项目中,并添加了我的相关 Web 服务配置。 我用来启动windows服务的代码是:

WebServiceHost webserviceHost = new WebServiceHost(typeof(MyService.Service1));
webserviceHost.Open();

Web 服务运行良好,但 Fiddler 在从 Web 浏览器进行调用时未检测到任何通过 GZIP 压缩返回的响应。我还尝试以编程方式使用 GZIP 设置和运行 Web 服务,但失败了。作为绿色我不确定我还需要配置什么,任何建议都很棒

我对此进行了深入研究,发现由于我将 Web 服务作为 WebServiceHost 对象运行,因此它必须使用 WebServiceHost 默认的 WebHTTPBinding 对象覆盖 app.conf 文件中的自定义 GZIP 绑定,即意味着来自 Web 服务的任何内容都不会被编码。 为了解决这个问题,我想我会以编程方式将自定义 GZIP 绑定写入代码

var serviceType = typeof(Service1);
var serviceUri = new Uri("http://localhost:8080/webservice");
var webserviceHost = new WebServiceHost(serviceType, serviceUri);
CustomBinding binding = new CustomBinding(new GZipMessageEncodingBindingElement(), new HttpTransportBindingElement());
var serviceEndPoint = webserviceHost.AddServiceEndpoint(typeof(IService), binding, "endpoint");
webserviceHost.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
webserviceHost.Open();

问题在于它不允许与 WebHttpBehavior 进行自定义绑定。但是,如果我删除该行为,那么我的 REST Web 服务就会变得丑陋,并期望 Stream 对象作为我的合同中的输入。我不确定如何配置行为,所以任何帮助都非常有用。

【问题讨论】:

    标签: c# .net wcf web-services gzip


    【解决方案1】:

    这是我花了几天时间想出的程序化解决方案。请注意,我不知道如何在 app.config 文件中配置解决方案,只能通过代码配置。 首先按照Link获取并修复微软编码示例中的GZIP类。然后使用下面的示例代码作为配置您自己的 Web 服务的基础。

    //Some class class to start up the REST web service
    public class someClass(){
        public static void runRESTWebservice(){
            webserviceHost = new WebServiceHost(typeof(Service1), new Uri("http://localhost:8080));
            webserviceHost.AddServiceEndpoint(typeof(IService), getBinding(), "webservice").Behaviors.Add(new WebHttpBehavior());
            webserviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        }
    
        //produces a custom web service binding mapped to the obtained gzip classes
        private static Binding getBinding(){
            CustomBinding customBinding = new CustomBinding(new WebHttpBinding());
            for (int i = 0; i < customBinding.Elements.Count; i++)
            {
                if (customBinding.Elements[i] is WebMessageEncodingBindingElement)
                {
                    WebMessageEncodingBindingElement webBE = (WebMessageEncodingBindingElement)customBinding.Elements[i];
                    webBE.ContentTypeMapper = new MyMapper();
                    customBinding.Elements[i] = new GZipMessageEncodingBindingElement(webBE);
                }
                else if (customBinding.Elements[i] is TransportBindingElement)
                {
                    ((TransportBindingElement)customBinding.Elements[i]).MaxReceivedMessageSize = int.MaxValue;
                }
            }
            return customBinding;
        }
    }
    
    //mapper class to match json responses
    public class MyMapper : WebContentTypeMapper{
        public override WebContentFormat GetMessageFormatForContentType(string contentType){
            return WebContentFormat.Json;
        }
    }
    
    //Define a service contract interface plus methods that returns JSON responses
    [ServiceContract]
    public interface IService{
        [WebGet(UriTemplate = "somedata", ResponseFormat = WebMessageFormat.Json)]
        string getSomeData();
    }
    
    //In your class that implements the contract explicitly set the encoding of the response in the methods you implement
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class Service1 : IService
    {
        public string getSomeData()
        {
            WebOperationContext.Current.OutgoingResponse.Headers[HttpResponseHeader.ContentEncoding] = "gzip";
            return "some data";
        }
    }
    

    我通过关注link 解决了大部分问题。

    注意:Microsoft 没有将 GZIP 本地构建到 WCF 中,这让我有些困惑,因为 WCF 是任何返回大量数据的 REST Web 服务的重要组成部分。

    【讨论】:

      【解决方案2】:

      作为对您关于 WCF 不支持 GZIP 的评论的回应,它已添加到 .Net 4.5 中。见here

      【讨论】:

        【解决方案3】:

        如果您使用的是 RestService 和 IIS (>=7.0),则不必自己执行此操作!

        IIS 7 支持动态压缩,允许自动压缩在您自己的应用程序(ASP.NET、MVC、WCF 或其他!)中创建的内容。该方案基于内容类型嗅探,因此适用于任何类型的 Web 应用程序框架。

        请找完整教程here

        【讨论】:

        • 恐怕我没有使用 IIS,而是将其作为自己的可执行 Windows 服务应用程序分发,因此不必依赖客户端设置自己的 IIS。
        • 我终于通过代码解决了这个问题。我是正确的,webServiceHost 需要自定义绑定,但需要在其构造函数中使用 WebHttpBinding 进行初始化,然后将 gzip 绑定元素映射到它和映射器。接下来,在实现 Web 服务器契约的每个方法中,您需要将响应标头内容编码显式更改为“gzip”。这个链接很有帮助social.msdn.microsoft.com/Forums/en-US/wcf/thread/…
        【解决方案4】:

        由于某种原因,我无法让上述实现适用于使用 Json + 压缩的自托管 WCF REST,仅适用于 XML。

        在沮丧的环顾了一段时间后,终于从下面最近的一篇博客中找到了解决方案。希望这对仍在寻找相同东西的人有所帮助。

        https://blogs.msdn.microsoft.com/carlosfigueira/2016/02/23/using-automatic-format-selection-with-a-compression-encoder-in-self-hosted-scenarios/

        【讨论】:

          猜你喜欢
          • 2011-03-26
          • 1970-01-01
          • 1970-01-01
          • 2011-06-10
          • 2020-02-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多