7

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

我已经按照链接Applying GZIP Compression to WCF Services指向下载添加 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 服务运行良好,但 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 对象作为我的合同中的输入。我不确定如何配置行为,所以任何帮助都非常有用。

4

4 回答 4

4

所以这是我花了几天时间提出的程序化解决方案。请注意,我不知道如何在 app.config 文件中配置解决方案,只能通过代码配置。首先按照此链接 获取并修复微软编码示例中的 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";
    }
}

我通过这个链接解决了这个问题。

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

于 2012-10-10T09:18:01.880 回答
3

为了回应您对 WCF 不支持 GZIP 的评论,它已添加到 .Net 4.5 中。见这里

于 2012-12-31T22:18:49.620 回答
0

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

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

请在此处找到完整的教程。

于 2012-10-09T11:01:59.270 回答
0

由于某种原因,我无法让上述实现适用于使用 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/

于 2016-03-15T04:33:15.570 回答