c#

Apache CXF と SilverLight3.0の連携


Visual Studio 2010 beta2で連携してみました。

...使えねー。......使いたくねー。
速度的には問題ないと思うんですが、如何せん作りにくいです。もの凄く。
まぁサーバー側がMSから脱却できるってだけでも御の字でしょうね。
何が悲しくてIISなんぞ...。


先ずはサーバーサイド。Apache CXFです。大体コ コと一緒。

必要になるライブラリ一覧(若干余計なものも混じってますが)

[ WEB-INF\lib ]
---------------
aopalliance-1.0.jar
backport-util-concurrent.jar
cglib-nodep-2.1_3.jar
commons-beanutils.jar
commons-digester.jar
commons-fileupload.jar
commons-io.jar
commons-logging.jar
cxf-2.1.5.jar
FastInfoset-1.2.3.jar
flex-messaging-common.jar
flex-messaging-core.jar
flex-messaging-remoting.jar
geronimo-annotation_1.0_spec-1.1.1.jar
geronimo-servlet_2.5_spec-1.2.jar
geronimo-stax-api_1.0_spec-1.0.1.jar
geronimo-ws-metadata_2.0_spec-1.1.2.jar
ibatis-2.3.4.726.jar
jaxb-api-2.1.jar
jaxb-impl-2.1.9.jar
lib.txt
neethi-2.0.4.jar
opensaml-1.1.jar
pjl-comp-filter-1.6.5.jar
postgresql-8.3-603.jdbc4.jar
saaj-api-1.3.jar
saaj-impl-1.3.2.jar
serializer-2.7.1.jar
spring-aop.jar
spring-beans.jar
spring-context-support.jar
spring-context.jar
spring-core.jar
spring-jdbc.jar
spring-orm.jar
spring-tx.jar
spring-web.jar
sql-map-2.dtd
sql-map-config-2.dtd
wsdl4j-1.6.2.jar
wss4j-1.5.7.jar
wstx-asl-3.2.6.jar
xalan-2.7.1.jar
xml-resolver-1.2.jar
XmlSchema-1.4.5.jar
xmlsec-1.4.2.jar
---------------

[ 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-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>


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

[ cxf.xml ]
---------------
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:jaxws="http://cxf.apache.org/jaxws"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
                     http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://cxf.apache.org/jaxws
                     http://cxf.apache.org/schemas/jaxws.xsd">

    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

    <jaxws:endpoint id="sl" implementor="com.chocbanana.ws.SilverLight" address="/SilverLight" />
</beans>
[EOF]
---------------

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

import javax.jws.WebMethod;

public interface ISl {
    
    @WebMethod
    public String getHello(String str);
}
[EOF]
---------------

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

import javax.jws.WebMethod;

public class SilverLight implements ISl {
    
    @WebMethod
    public String getHello(String str){
        return ("Hello " + str + ", Wellcome to SilverLight world !");
    }
}
[EOF]
---------------

ここまでがサーバー側。問題なしでしょう。



ここからSilverLight。
VisualStudio 2010 beta2.0なので、製品版とは多少異なるかもしれません。あしからず。


SilverLightのプロジェクトを作成。今回はC#で。っていうかVBなんぞで作って(作られて)堪るか。
SilverLightでの最大の注釈。Svcutil.exeでのスタブ作成したコードは使用出来ません。
[ サービス参照の追加 ] より、WSDLのURIを指定して下さい。

さて困りました。スタブを作成して開発していた時は普通に呼べたメソッドがCall出来ません。
(もうこの時点で9割方どーでも良くなりました。Flexで良いやn(ry)

解説するのもメンドクサクナッタノデ、ソースコピペして置きます。
ご参考までに。

[ My Documents\Visual Studio 2010\Projects\sa1\sa1 ]
---------------
App.xaml
App.xaml.cs
Bin
MainPage.xaml
MainPage.xaml.cs
obj
Properties
sa1.csproj
sa1.csproj.user
Service References
ServiceReferences.ClientConfig
---------------


[ MainPage.xaml ]
---------------
<UserControl x:Class="sa1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="155,119,0,0" Name="btn_test" VerticalAlignment="Top" Width="75" Click="btn_test_Click" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="12,90,0,0" Name="txt_box" VerticalAlignment="Top" Width="376" />
    </Grid>
</UserControl>
[ EOF ]
---------------


えー、見て分かるように、Webサービスの呼び出しがEventDrivenです。
普通に txt_box.Text = scl.getHello(txt_box.Text); ってやりたいだけでこのコード量。
泣けます。
readConfig();はちょっとしたテクニック...なのかも。


[ MainPage.xaml.cs ]
---------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Xml;
using System.Xml.Linq;
using System.ServiceModel;

namespace sa1
{
    public partial class MainPage : UserControl
    {
        private ServiceRef.SilverLightClient scl;
        private ServiceRef.getHello hello;

        public MainPage()
        {
            InitializeComponent();
        }

        #region CallWebService
        private void CallWebService(string value)
        {
            scl = this.GetSilverLightClient();
            hello = this.GetHelloClient();
            
            scl.getHelloCompleted += new EventHandler<ServiceRef.getHelloCompletedEventArgs>(client_GetHelloCompleted);

            hello.Body.arg0 = value;
            scl.OpenAsync();
            scl.getHelloAsync(hello);
            scl.CloseAsync();

        }
        private ServiceRef.SilverLightClient GetSilverLightClient() {
            ServiceRef.SilverLightClient scl;
            string uri = readConfig();

            if (uri != "")
            {
                if (uri.StartsWith("https://") == true)
                {
                    scl = new ServiceRef.SilverLightClient("SilverLightPort_Security", new EndpointAddress(uri));
                }
                else
                {
                    scl = new ServiceRef.SilverLightClient("SilverLightPort", new EndpointAddress(uri));
                }
            }
            else
            {
                scl = new ServiceRef.SilverLightClient();
            }
            return scl;
        }
        private ServiceRef.getHello GetHelloClient()
        {
            ServiceRef.getHello hello;
            hello = new ServiceRef.getHello(new ServiceRef.getHelloBody());
            return hello;
        }
        private string readConfig()
        {
            Uri docUri = System.Windows.Browser.HtmlPage.Document.DocumentUri;
            Uri svcUri = new Uri(docUri, "/services/SilverLight");
            return svcUri.ToString();
        }
        private void client_GetHelloCompleted(object sender, ServiceRef.getHelloCompletedEventArgs e)
        {
            try
            {
                txt_box.Text = e.Result.Body.@return.ToString();
            }catch(Exception ex){
                MessageBox.Show(ex.InnerException.Message);
            }
        }
        #endregion

        private void btn_test_Click(object sender, RoutedEventArgs e)
        {
            string value = txt_box.Text;

            if (value == "")
            {
                value = "Guest User";
            }
            this.CallWebService(value);
        }
    }
}
[ EOF ]
---------------

なんかさー、仕様的に、EventDriven持ってくるとかオカシくね?
普通にCallしたいだけなんよ?
あー、あれか、Webサービス呼び出し用のコントローラー作って隠蔽しないとダメなのか。
そっか、そっか、そっか...。orz

■ 追記
えー、隠蔽出来ませんでした。Viewとなる.csに直書きです。もう嫌です。なんでこんなクソ仕様...。orz



このファイル (ServiceReferences.ClientConfig) は [Webサービス参照] 時にService Referencesディレクトリと共に生成されます。
scl = new ServiceRef.SilverLightClient("SilverLightPort", new EndpointAddress(uri));
部分にて、Binding名を参照しております。

■追記
あー、一応HTTPSにも対応ですね。

[ ServiceReferences.ClientConfig ]
---------------
<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="SilverLightServiceSoapBinding" maxBufferSize="2147483647"
                    maxReceivedMessageSize="2147483647">
                    <security mode="None" />
                </binding>
                <binding name="SilverLightServiceBinding_Security" maxBufferSize="2147483647"
                    maxReceivedMessageSize="2147483647">
                    <security mode="Transport" />
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://127.0.0.1:8080/services/SilverLight"
                binding="basicHttpBinding" bindingConfiguration="SilverLightServiceSoapBinding"
                contract="ServiceRef.SilverLight" name="SilverLightPort" />
            <endpoint address="https://127.0.0.1:8443/services/SilverLight"
                binding="basicHttpBinding" bindingConfiguration="SilverLightServiceBinding_Security"
                contract="ServiceRef.SilverLight" name="SilverLightPort_Security" />
        </client>
    </system.serviceModel>
</configuration>
[ EOF ]
---------------

出来上がりです。

cxf_silverlight.jpg
このページの先頭へ