在 C# 中将 GZIP 添加到 WCF REST 服务

2023-12-23

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

我已点击链接将 GZIP 压缩应用于 WCF 服务 http://blogs.msdn.com/b/dmetzgar/archive/2011/03/10/compressing-messages-in-wcf-part-one-fixing-the-gzipmessageencoder-bug.aspx这指向添加 GZIP 的 Microsoft 示例的下载,但该示例与我设置 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 服务运行良好,但从 Web 浏览器进行调用时,Fiddler 未检测到任何通过 GZIP 压缩返回的响应。我还尝试以编程方式使用 GZIP 设置和运行 Web 服务,但惨败。作为绿色我不知道我还需要配置什么,任何建议都非常有用

我对此进行了更深入的研究,发现由于我将Web服务作为WebServiceHost对象运行,因此它必须使用WebServiceHost默认的WebHTTPBinding对象覆盖app.conf文件中的自定义GZIP绑定,这意味着任何事情都会发生网络服务之外的内容将不会被编码。 为了解决这个问题,我想我会以编程方式将自定义 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 对象作为我的合约中的输入。我不确定如何配置行为,因此任何帮助都非常有用。


这是我花了几天时间想出的程序化解决方案。请注意,我不知道如何在 app.config 文件中配置解决方案,而只能通过代码。 首先按照这个Link http://blogs.msdn.com/b/dmetzgar/archive/2011/03/10/compressing-messages-in-wcf-part-one-fixing-the-gzipmessageencoder-bug.aspx获取并修复 Microsoft 编码示例中的 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 http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/8c3eafae-b6a1-441f-85ef-90721d941a1a.

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 C# 中将 GZIP 添加到 WCF REST 服务 的相关文章

随机推荐