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

Mr *_*owe 7 .net c# wcf gzip web-services

我在C#.NET WCF Web服务上启用GZIP压缩时遇到了麻烦,并希望有人可能知道我在App.conf配置文件中缺少的内容,或者在调用启动Web服务时需要多少额外费用代码.

我已经按照将GZIP压缩应用到WCF服务的链接指向下载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>
Run Code Online (Sandbox Code Playgroud)

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

WebServiceHost webserviceHost = new WebServiceHost(typeof(MyService.Service1));
webserviceHost.Open();
Run Code Online (Sandbox Code Playgroud)

webservice运行正常,但是当从Web浏览器拨打电话时,Fiddler没有检测到任何带有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();
Run Code Online (Sandbox Code Playgroud)

问题是它不允许与WebHttpBehavior进行自定义绑定.但是如果我删除了这个行为,那么我的REST Web服务变得丑陋,并期望Stream对象作为我合同中的输入.我不确定如何配置行为,所以任何帮助都很棒.

Mr *_*owe 4

这是我花了几天时间想出的程序化解决方案。请注意,我不知道如何在 app.config 文件中配置解决方案,而只能通过代码。首先点击此链接 获取并修复 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";
    }
}
Run Code Online (Sandbox Code Playgroud)

我通过点击此链接解决了大部分问题。

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