c#

WCFでGZip圧縮(WCF Client と Apache CXF + pjl-comp-filter)


.NET Framework3.5 SP1 以降。Windows XP 以降に対応です。

WCFでの実装になりますが、WS-Security(HTTPS)を利用する場合、残念ながらこの機能は利用出来ません。
SOAP(HTTP)でなら、GZipでの圧縮が有効になります。


えー、出来ましたので、別 途掲載させて頂きます。m(_"_)m

開発環境は VisualStudio 2008 C# です。


まずはサービス側。

pjl-comp-filter でGzip圧縮します。pjl-comp-filter.jar と web.xmlだけでOKです。

[ web.xml ]
----------------------
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <display-name>Service</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/com/chocbanana/ws/cxf.xml</param-value>
    </context-param>

    <!-- Filter config with GZIP -->
    <filter>
        <filter-name>CompressingFilter</filter-name>
        <filter-class>
            com.planetj.servlet.filter.compression.CompressingFilter
        </filter-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>statsEnabled</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>CompressingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

   
    <servlet>
        <servlet-name>context</servlet-name>
        <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
        <init-param>
            <param-name>services.configuration.file</param-name>
            <param-value>/WEB-INF/flex/services-config.xml</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>ScheduleStarter</servlet-name>
        <servlet-class>com.chocbanana.schedule.ScheduleStarter</servlet-class>
        <load-on-startup>4</load-on-startup>
    </servlet>

    <servlet>
          <servlet-name>FileUpServlet</servlet-name>
          <servlet-class>com.chocbanana.csv.Upload</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>FileUpServlet</servlet-name>
        <url-pattern>/fileup/*</url-pattern>
    </servlet-mapping>

    <mime-mapping>
        <extension>wsdl</extension>
        <mime-type>text/xml</mime-type>
    </mime-mapping>
</web-app>
[ EOF ]
----------------------

[ com.chocbanana.ws.Service.java ]
----------------------
package com.chocbanana.ws;

import javax.jws.WebService;
import javax.jws.WebMethod;

@WebService
public class Service implements IService{

    public Service(){
    }
       
    @WebMethod
    public String hello(){
        return "Hello";
    }
}
[ EOF ]
----------------------


んで、WCF側。


前準備としてGZipライブラリが必要になるので、それを用意します。

http://www.microsoft.com/Downloads/details.aspx?familyid=ED9C315C-31AC-4CCB-B62B-721AF1E2BFA8&displaylang=en
より WCF_WF_Samples.exe をダウンロードします。

それを解凍した中に、WCFWFCardSpace\WCF\Extensibility\MessageEncoder\Compression\CS があるので、それをVS2008で少し改変してビルドしておきます。
このソリューションのビルドが成功すると GZipEncoder.dll が作成されますので、GZip圧縮にはこのDLLを利用します。

以下改変部分。

-------------
1) GZipMessageEncoderFactory.cs
        //This is the actual GZip encoder
        class GZipMessageEncoder : MessageEncoder
        {
            //static string GZipContentType = "application/x-gzip";
            static string GZipContentType = "text/xml"; // 置換

2) GZIPMessageEncodingBindingElement.cs
        public GZipMessageEncodingBindingElement(MessageEncodingBindingElement messageEncoderBindingElement)
        {
            this.innerBindingElement = messageEncoderBindingElement;
            this.innerBindingElement.MessageVersion = MessageVersion.Soap11; // 追加
        }
-------------


あとは以 前作ったこのコードとapp.configに修正を加えます。
使用するプロジェクトにGZipEncoder.dll をインポートして、Microsoft.ServiceModel.Samplesの参照設定を行って下さい。

以下サンプル用ソースコード。

[ app.config ]
-----------------------
<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <section name="WCF_TEST.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
    </sectionGroup>
  </configSections>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ClientCredentialsBehavior">
          <clientCredentials>
            <serviceCertificate>
              <authentication certificateValidationMode="None" revocationMode="NoCheck"/>
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <extensions>
      <bindingElementExtensions>
        <add name="gzipMessageEncoding" type="Microsoft.ServiceModel.Samples.GZipMessageEncodingElement, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </bindingElementExtensions>
    </extensions>

    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_Service" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="Transport">
            <transport clientCredentialType="None" proxyCredentialType="None"
              realm="" />
            <message algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
      <customBinding>
        <binding name="ISampleServer">
          <gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />
          <httpTransport manualAddressing="false" authenticationScheme="None"
            bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            proxyAuthenticationScheme="Basic" realm="" useDefaultWebProxy="false" />
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="https://127.0.0.1:8443/services/Service" behaviorConfiguration="ClientCredentialsBehavior"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_Service"
        contract="ims.IService" name="BasicHttpBinding_Service" />
      <endpoint address="http://127.0.0.1:8080/services/Service" binding="customBinding"
        bindingConfiguration="ISampleServer" contract="ims.IService"
        name="SoapBinding_Service" />
      <metadata>
        <policyImporters>
          <extension type="Microsoft.ServiceModel.Samples.GZipMessageEncodingBindingElementImporter, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </policyImporters>
      </metadata>
    </client>
  </system.serviceModel>

  <applicationSettings>
    <WCF_TEST.Properties.Settings>
      <setting name="ProxyServer" serializeAs="String">
        <value>http://proxyserver:8080/</value>
      </setting>
      <setting name="OutputFile" serializeAs="String">
        <value>detault.xml</value>
      </setting>
      <setting name="OutputFileFlag" serializeAs="String">
        <value>FALSE</value>
      </setting>
      <setting name="Debug" serializeAs="String">
        <value>FALSE</value>
      </setting>
      <setting name="ProxyEnabled" serializeAs="String">
        <value>FALSE</value>
      </setting>
      <setting name="Domain" serializeAs="String">
        <value>DOMAIN</value>
      </setting>
      <setting name="AdminUser" serializeAs="String">
        <value>Administrator</value>
      </setting>
      <setting name="AdminPass" serializeAs="String">
        <value>password</value>
      </setting>
      <setting name="AdminDomain" serializeAs="String">
        <value>LONDON</value>
      </setting>
      <setting name="EncryptPassword" serializeAs="String">
        <value>OFF</value>
      </setting>
      <setting name="Binding" serializeAs="String">
        <value>SoapBinding_Service</value>
      </setting>
      <setting name="Address" serializeAs="String">
        <value>https://chocbanana.com/services/Service</value>
      </setting>
      <setting name="SOAP_Address" serializeAs="String">
        <value>http://chocbanana.com/services/Service</value>
      </setting>
    </WCF_TEST.Properties.Settings>
  </applicationSettings>
  <startup>
    <supportedRuntime version="v2.0.50727"/>
  </startup>
</configuration>
[ EOF ]
-----------------------


[ Program.cs ]
-----------------------
using System;
using System.Collections.Generic;
using System.Text;
using ims;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.ServiceModel.Samples;
using System.Net;

namespace WCF_TEST {
    class Program {
        static void Main(string[] args) {
            try {
                show();
            } catch (Exception e) {
                Console.WriteLine("msg: " + e.Message);
                Console.WriteLine("data: " + e.Data);
                Console.WriteLine("src: " + e.Source);
                Console.WriteLine("trace: " + e.StackTrace);
            }
        }

        private static void show() {
            string Address = Properties.Settings.Default.Address;
            string Binding = Properties.Settings.Default.Binding;
            ServiceClient service = null;
            if (Address.StartsWith("https://") && Binding == "BasicHttpBinding_Service") {

                //証明書の確認用EvnetHandlerをコール
                ConfirmCertificatePolicy.ConfirmCertificatePolicy_CallEventHandler();
                ims.ServiceClient proxy = new ims.ServiceClient("BasicHttpBinding_Service",
                    new System.ServiceModel.EndpointAddress(Properties.Settings.Default.Address));
                string proxyEnabled = Properties.Settings.Default.ProxyEnabled;

                if (proxyEnabled == "TRUE") {
                    string proxyServer = Properties.Settings.Default.ProxyServer;
                    BasicHttpBinding httpBindingElement = (BasicHttpBinding)proxy.Endpoint.Binding;
                    httpBindingElement.BypassProxyOnLocal = true;
                    httpBindingElement.UseDefaultWebProxy = false;
                    httpBindingElement.ProxyAddress = new Uri(proxyServer);
                    proxy.Endpoint.Binding = httpBindingElement;
                }

                Console.WriteLine(proxy.hello());
                proxy.Close();

            } else {
                ICollection<BindingElement> bindingElements = new List<BindingElement>();
                HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
                string proxyEnabled = Properties.Settings.Default.ProxyEnabled;
                if (proxyEnabled == "TRUE") {
                    string proxyServer = Properties.Settings.Default.ProxyServer;
                    httpBindingElement.BypassProxyOnLocal = true;
                    httpBindingElement.UseDefaultWebProxy = false;
                    httpBindingElement.ProxyAddress = new Uri(proxyServer);
                }

                //httpBindingElement.AuthenticationScheme = AuthenticationSchemes.Basic;

                GZipMessageEncodingBindingElement compBindingElement = new GZipMessageEncodingBindingElement();
                bindingElements.Add(compBindingElement);
                bindingElements.Add(httpBindingElement);

                CustomBinding myBinding = new CustomBinding(bindingElements);
                myBinding.Name = "SoapBinding_Service";
                myBinding.Namespace = "http://ws.chocbanana.com/";


                // Webサービスインスタンス生成 //
                Address = Properties.Settings.Default.SOAP_Address;
                service = new ims.ServiceClient(myBinding, new EndpointAddress(Address));

                HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();

                httpRequestProperty.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");
                httpRequestProperty.Headers.Add(HttpRequestHeader.ContentEncoding, "gzip");

                using (OperationContextScope scope = new OperationContextScope(service.InnerChannel)) {
                    OperationContext.Current.OutgoingMessageProperties
                    [HttpRequestMessageProperty.Name] = httpRequestProperty;
                    Console.WriteLine(service.hello());
                }
            }
        }
    }
}
[ EOF ]
-----------------------

参考サイトURL
http://www.vistax64.com/indigo/113763-wcf-client-j2ee-server-using-gzip.html

このページの先頭へ