Hatena::Groupmediaforcelabs

御手洗の開発記録

2010-06-17

Silverlight対応WCFサービスの同期実行について

| 18:27

こんにちは。

Silverlightからバッグ側の処理を実行するために、Silverlight対応WCFサービスを利用しています。

何も考えず実装すると非同期実行になってしまいますが、どうしても同期実行がしたいのでいろいろ調べてみました。

結論から言うと、Silverlight対応WCFサービスでは同期実行が出来ませんでした。

自分は以下の2つの方法を試してみました。


1.AutoResetEventを使って非同期実行の終了を待つ方法

AutoResetEventやManualResetEventを利用して別スレッドで起動している(はず)終了処理の完了を待機する方法を試してみました。

ソースは以下の通りです。

namespace SilverlightWCFTest
{
    public partial class MainPage : UserControl
    {
        private AutoResetEvent are = new AutoResetEvent(false);

        public MainPage()
        {
            InitializeComponent();

            // サービスを非同期で実行する
            var proxy = new EchoServiceClient();
            proxy.GetMessageCompleted += new EventHandler<GetMessageCompletedEventArgs>(proxy_GetMessageCompleted);
            proxy.GetMessageAsync();

            // proxy_GetMessageCompletedメソッド終了まで待機する
            are.WaitOne();
        }

        void proxy_GetMessageCompleted(object sender, GetMessageCompletedEventArgs e)
        {
            // 画面に結果内容を反映する
            MainPageContext context = (MainPageContext)Resources["Context"];
            context.Message = e.Result;

            // 完了を通知する
            are.Set();
        }
    }
}

この方法でやると、なぜかproxy_GetMessageCompletedが実行されません。

スレッドIDを確認すると、別のスレッドになっているようですが、なぜかWaitOne()で止まったままになってしまいます。


2.チャネルモデルでWCFを実行する方法

IAsyncResultにAsyncWaitHandleというプロパティがあったので、そのオブジェクトを使用して同期する方法を試してみました。

ソースは以下の通りです。

namespace SilverlightWCFTest
{
    public partial class MainPage : UserControl
    {
        SynchronizationContext uiThread;

        public MainPage()
        {
            InitializeComponent();

            uiThread = SynchronizationContext.Current;

            // チャネルモデルのサービスを生成して実行する
            var channel = new EchoServiceClient().ChannelFactory.CreateChannel();
            IAsyncResult asyncResult = channel.BeginGetMessage(GetMessageCallback, channel);

            // サービス完了まで待機する
            ((ManualResetEvent)asyncResult.AsyncWaitHandle).WaitOne();
        }

        private void GetMessageCallback(IAsyncResult asyncResult)
        {
            string message = ((EchoService)asyncResult.AsyncState).EndGetMessage(asyncResult);

            // 画面を更新する
            uiThread.Post(UpdateUI, message);

            // 処理の終了を通知する
            ((ManualResetEvent)asyncResult.AsyncWaitHandle).Set();
        }

        private void UpdateUI(object obj)
        {
            MainPageContext context = (MainPageContext)Resources["Context"];
            context.Message = (string)obj;
        }
    }
}

このやり方でもGetMessageCallback()メソッドが実行されず、WaitOne()で止まったままになってしまいます。

その他にもいろいろ調査してみましたが、結局同期実行はできませんでした。

一番不可解なのは、1のやり方で同期実行ができなかったことです。

この方法はWCFというよりも.NET FrameworkAPIを使っているはずなのですが、別スレッドになっているはずの処理が実行されませんでした。

自分の勉強不足で根本的に何か間違えているのかもしれませんが、ちょっと納得がいかないです。

今後、時間のあるときに再度調査していきたいと思います。

それでは、また。

CristinitaCristinita2012/02/20 14:02Now that's stuble! Great to hear from you.

hmrnetspqzzhmrnetspqzz2012/02/21 18:19ysqMY3 <a href="http://pfdwclitxnhy.com/">pfdwclitxnhy</a>

wiqvtymmrwiqvtymmr2012/02/21 22:20DmQpO9 , [url=http://ozqvrzwpumgd.com/]ozqvrzwpumgd[/url], [link=http://pfanabyotmfu.com/]pfanabyotmfu[/link], http://enlbfxbqqkol.com/

yzehriftghyzehriftgh2012/02/29 02:25B00Kkc <a href="http://vsykehbryolr.com/">vsykehbryolr</a>

2010-06-10

System.Collections.Generic.SortedListがSilverlightアプリケーションプロジェクトから参照できません。

| 17:13

こんにちは。

あまりの衝撃で、ちょっとタイトルが長くなってしまいました。

Visual Studio 2010でSilverlightアプリケーションのプロジェクトを作成したのですが、System.Collections.Generic.SortedListが参照できません。

これは、プロジェクトが参照しているDLLに問題があるようです。

オブジェクトブラウザを見てみて気付いたのですが、Silverlightアプリケーションで参照しているプロジェクトは「Microsoft\Framework\Silverlight\v4.0\system.dll」を参照しています。

そのDLLでは以下のクラスしかありません。

f:id:mitarai2009:20100610165741p:image

SortedListが見当たりません。

で、先ほどの画像をよく見てみると、下の方に同じSystemパッケージが見えます。

f:id:mitarai2009:20100610165742p:image

こちらのほうには、SortedListがあります。

参照しているDLLは「Microsoft\Framework\.NETFramework\v4.0\System.dll」となっています。

「なるほど、参照しているDLLを変更すればいいのか」と思い、DLLを「Microsoft\Framework\.NETFramework\v4.0\System.dll」に変更してみましたが、エラーが発生します。

f:id:mitarai2009:20100610165743p:image

英語は読めないので勘を働かせてこの文字列を翻訳してみました。

おそらく、「SilverlightランタイムではSystem.dllは使用できません。」みたいなことを言ってるんでしょう。

うーーん。

で、どうしよう。←いまここ

なんか、こういうのを質問する窓口みたいなのはないんでしょうか?

まあ、あったとしても英文が書けないので質問できないんですけどねw

なにか、やり方があれば教えてください。

それでは、また。

LuisanaLuisana2012/03/23 05:23It's about time somneoe wrote about this.

armbfyharmbfyh2012/03/23 20:37NOBsrd , [url=http://xytdwgdiexdp.com/]xytdwgdiexdp[/url], [link=http://dxkcralfmkxl.com/]dxkcralfmkxl[/link], http://qauccajpabbv.com/

xtzwitxtzwit2012/03/25 07:257LY1xP <a href="http://lukresuiqkro.com/">lukresuiqkro</a>

sjfsdyrwhsjfsdyrwh2012/03/25 10:14DZbdH3 , [url=http://dwxfnbbcvune.com/]dwxfnbbcvune[/url], [link=http://smnsqhmplsxz.com/]smnsqhmplsxz[/link], http://aebcvuusdfii.com/

2010-06-03

SQL ServerでS2JDBC-GENを利用する方法

| 14:47

前々回、S2JDBC-GENでのマイグレーションについて書くと言っていましたが、特に難しいことはないので、注意点だけまとめることにします。

SQL ServerJDBCドライバのセットアップ方法

Javaで利用するので、JDBCドライバが必要です。

SQL ServerJDBCドライバMicrosoft公式のものとjTDSというプロジェクトが開発したものがあります。

DoltengS2JDBCのプロジェクトを作成すると、jTDSのJDBCドライバを利用するためのテンプレートが用意されています。

今日は、そんなに書くこともないので両方の記述方法を説明しておきます。

Microsoft公式のJDBCドライバを利用する方法

まず、以下のサイトからライセンス条項をダウンロードします。

http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=99b21b65-e98f-4a61-b811-19912601fdc9

Windowsで利用するので、ライセンス条項の「上記事項に同意し、Microsoft Windows バージョンをダウンロードします」をクリックしてドライバダウンロードします。

ダウンロードしたexeは自己解凍方式の実行ファイルなので、実行して解凍してできたモジュールを適切なディレクトリにコピーします。

ちなみに、僕は「C:\Program Files」配下にコピーしました。

次にjdbc.diconの設定方法です。

<component name="xaDataSource"
    class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
    <property name="driverClassName">
        "com.microsoft.sqlserver.jdbc.SQLServerDriver"
    </property>
    <property name="URL">
        "jdbc:sqlserver://localhost;integratedSecurity=true;instanceName=SQLEXPRESS;DatabaseName=DBNAME"
    </property>
</component>

今回は、統合認証を行っているので、ユーザ名とパスワードの設定は必要ありません。

そのかわり、「integratedSecurity=true」の設定が必須なのと、統合認証用DLLをPATHが通っているディレクトリにコピーしてください。(もしくは、DLLが格納されているディレクトリにパスを通す)

コピーしたDLLは以下の通りです。

Microsoft SQL Server JDBC Driver 2.0\sqljdbc_2.0\jpn\auth\x86\sqljdbc_auth.dll*1 *2

最後に、ドライバjarファイルのパスをクラスパスに設定します。

使用したjarファイルは以下の通りです。

Microsoft SQL Server JDBC Driver 2.0\sqljdbc_2.0\jpn\sqljdbc4.jar*3

以上でMicrosoft公式JDBCドライバの設定は終了です。


jTDSのJDBCドライバを利用する方法

jTDSのサイトからJDBCドライバダウンロードします。

公式サイト:http://jtds.sourceforge.net/

ダウンロードhttp://sourceforge.net/projects/jtds/files/

ダウンロードしてきたzipファイルを解凍して適切なディレクトリにコピーします。

次にjdbc.diconの設定方法です。

<component name="xaDataSource"
    class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
    <property name="driverClassName">
        "net.sourceforge.jtds.jdbc.Driver"
    </property>
    <property name="URL">
        "jdbc:jtds:sqlserver://localhost/DBNAEM;instance=SQLEXPRESS"
    </property>
</component>

上記の設定と同様に統合認証を行っているので、ユーザ名とパスワードの設定は必要ありません。

公式と違うのはDLLをコピーするだけで統合認証が利用できます。

コピーしたDLLは以下の通りです。

「jtds-1.2.5-dist\x86\SSO\ntlmauth.dll*4 *5

最後に、ドライバjarファイルのパスをクラスパスに設定します。

使用したjarファイルは以下の通りです。

「jtds-1.2.5-dist\jtds-1.2.5.jar*6

以上でMjTDSのJDBCドライバの設定は終了です。


SQL Serverのデータ型について

最後に、データ型を指定する方法を記載ます。

S2JDBCDDLを作成すると意図したデータ型にならない場合があります。

例えば、Date型で設定していたのにDateTime型になってしまったり、nvarcharがvarcharになってしまったりします。

そいうときは、ColumnアノテーションのcolumnDefinition属性で指定することができます。

@Column(nullable = true, unique = false, columnDefinition = "nvarchar(MAX)")
public String cn;

本日は以上で終了です。

あー。ラーメン食べたい。

*1解凍してできたディレクトリ名が「Microsoft SQL Server JDBC Driver 2.0」の場合の例となります。

*2: 64bit OS の場合はx64ディレクトリ配下のDLLを使用してください。

*3解凍してできたディレクトリ名が「Microsoft SQL Server JDBC Driver 2.0」の場合の例となります。

*4解凍してできたディレクトリ名が「jtds-1.2.5-dist」の場合の例となります。

*5: 64bit OS の場合はx64ディレクトリ配下のDLLを使用してください。

*6解凍してできたディレクトリ名が「jtds-1.2.5-dist」の場合の例となります。

BrunaBruna2012/02/18 14:22That's the smart thiknnig we could all benefit from.

njbcdwnjbcdw2012/02/19 19:49jTslcQ <a href="http://ddmargqbnzdf.com/">ddmargqbnzdf</a>

ygmktgutufvygmktgutufv2012/02/20 00:12gype8F , [url=http://pttmxelfkeee.com/]pttmxelfkeee[/url], [link=http://drudigdfwkzg.com/]drudigdfwkzg[/link], http://hieclwqosavc.com/

yepcnpmxfgmyepcnpmxfgm2012/02/26 02:21YXHrOO <a href="http://ayrasgbojlmz.com/">ayrasgbojlmz</a>

2010-05-27

Silverlightのフォーム認証について(Active Directoryとの認証)

| 15:15

今日は、Silverlightでフォーム認証を実装する方法をまとめておきます。

システム構成

まずは、システムの構成から説明します。

Silverlight自体はブラウザ上で動作するクライアントアプリケーションなので、利用者情報を取得する際は、サーバ側にリクエストしてデータを取得します。

その際、WCFを利用します。

WCFとは、Windows Communication Foundationの略で、簡単にいうとWebサービスです。

今回は利用者情報などの個人情報を扱うので認証が必要になります。

認証は当然、独自の実装をすることもできるのですが、今回はフォーム認証を利用することにしました。

WCFの認証サービスについては以下の通りです。

サービスを使用するには、認証サービスにユーザーの資格情報を渡します。認証サービスでは、ASP.NET メンバーシップを使用して渡された資格情報の妥当性を検査します。


既定では、認証サービスは、ユーザー名およびパスワードを既定のメンバーシップ プロバイダーに渡すことで、妥当性を検査します。ユーザーが認証されると、ASP.NET 認証サービスは、ASP.NET フォーム認証と互換性がある HTTP Cookie として認証チケットを発行します。


以降の要求では、毎回ユーザーが資格情報を入力しなくてもよいように、このチケットが Web アプリケーションに渡されます。

参考URLhttp://msdn.microsoft.com/ja-jp/library/bb386582.aspx

図に表すとこんな感じです。

f:id:mitarai2009:20100527151436p:image

このような処理が設定だけで実現することができます。

サーバ側の設定

今回は、

サーバ側の設定は以下の通りです。

基本は、MSDNを参考にして書いています。

参考URLhttp://msdn.microsoft.com/ja-jp/library/dd560704(v=VS.95).aspx

1.Silverlight対応のWCFサービスを作成します。

ソリューション エクスプローラーで、サービス プロジェクトを右クリックし、[追加]、[新しい項目] の順にクリックして、[Silverlight] カテゴリから [Silverlight 対応の WCF サービス] テンプレートを選択します。

その際、[名前] ボックスに「Authentication.svc」と入力し、[追加] ボタンをクリックします。(サービス名はなんでもいいと思うが、今回はマニュアルに従いました)

2.Authentication.svc.cs ファイルを削除します。
3.Authentication.svc の内容を次のコードに置き換えます。
<%@ ServiceHost Language="C#" Debug="true" Service="System.Web.ApplicationServices.AuthenticationService" %>
4.Web.ConfigファイルにauthenticationService要素を追加し、認証サービスを有効化します。

以下の設定をWeb.Configファイルに追加してください。(configuration要素の子要素として追加してください)

<system.web.extensions>
  <scripting>
    <webServices>
      <authenticationService enabled="true" requireSSL="false" />
    </webServices>
  </scripting>
</system.web.extensions>

まだ、開発途中なので、requireSSL属性がfalseになってますが、リリース時にはtrueに変更する必要があります。

5.Web.config ファイルに記述されているservice要素の設定を変更します。

この要素は、1の時点でVisualStudioが自動で追加してくれています。

そのため、service属性のname属性の値と、service属性の子要素であるendpoint要素のcontract属性の値をSystem.Web.ApplicationServices.AuthenticationServiceに変更してください。

<service name="System.Web.ApplicationServices.AuthenticationService">
  <endpoint address="" binding="customBinding"
    bindingConfiguration="WorkManagementApplication.Web.Services.Authentication.customBinding0"
    contract="System.Web.ApplicationServices.AuthenticationService" />
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
6.フォーム認証を有効化します。

system.web要素の子要素としてauthentication要素を追加します。

その際、mode属性はFormsとします。

また、authentication要素の子要素としてforms要素を追加します。

その際、cookielessを追加し、値はUseCookiesを設定してください。

<authentication mode="Forms">
  <forms cookieless="UseCookies" />
</authentication>
7.メンバシッププロバイタをWeb.Configに設定します。

System.Web.ApplicationServices.AuthenticationServiceは認証の際にメンバシッププロバイダを利用して認証や資格情報の作成を行っています。

今回は、Active Directoryを使用して認証を実施するため、メンバシッププロバイダにはSystem.Web.Security.ActiveDirectoryMembershipProviderを使用します。

まずは、Active Directoryの接続情報を追加します。

<connectionStrings>
  <add name="ADConnectionString" connectionString="LDAP://%サーバアドレス%/%BaseDN%" />
</connectionStrings>

connectionStrings要素はconfiguration要素の子要素として追加します。

%サーバアドレス%にはActive Directoryサーバ名(IPアドレス)を設定し、%BaseDN%には利用者情報が格納されているディレクトリのDNを設定してください。

次に、メンバシッププロバイダをWeb.Configに追加します。

<membership defaultProvider="MembershipADProvider">
  <providers>
    <add name="MembershipADProvider"
      type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
      connectionStringName="ADConnectionString"
      connectionUsername="%ユーザ名%"
      connectionPassword="%パスワード%"
      attributeMapUsername="sAMAccountName" />
  </providers>
</membership>

membership要素はsystem.web要素の子要素として追加します。

connectionStringNameには、addのname属性で指定した文字列を設定してください。

%ユーザ名%と%パスワード%はActive Directoryの管理者ユーザを設定してください。

そして、attributeMapUsername属性は必ず指定してください。

この属性は、ユーザ名がどの属性に設定されているかどうか指定する属性となります。

この属性を設定しないと認証に成功しません。

このおかげで、結構はまりました。

ホント、MSDNは一言足りないと思います!!!

ちなみに、値はsAMAccountNameを設定しておけばまず間違いありません。

8.サービスのアクセス権限を設定します。

制限をかけたいサービスのアクセス権限を設定します。

今回は、指定したディレクトリ配下のサービスに匿名ユーザからのアクセスを禁止する設定を行いました。

方法は以下の通りです。

サービスを専用のディレクトリ ("secure/MyService.svc" など) に置き、そのディレクトリの構成ファイル ("secure/Web.config" など) を以下のような設定にします。

<configuration>
    <system.web>
      <authorization>
        <deny users="?" />
      </authorization>
    </system.web>
</configuration>

ちなみに、この設定を行うと、Silverlightプロジェクト側でサービス参照の追加や更新ができなくなります。

そのため、開発時にはまずサービスを作成し、インタフェースが定まったらWeb.Configを追加するという流れにしないめんどうです。

一応、authorizationの設定をコメントアウトにして更新して、コメントを元に戻すというやり方でサービス参照の更新は可能ですが、めんどくさいですよね。

なんかいい方法があるのかもしれませんが、それほど優先順位は高くないのでこのまま突き進みます。

以上でサーバ側の設定が完了です。

クライアント側(Silverlight)の設定

クライアント側は特に特別なことをする必要はありません。

認証サービスと制限のかかったサービスをサービス参照に追加し、サービスの実行を実装します。

サンプルとしては以下の通りです。

private void loginButton_Click(object sender, RoutedEventArgs e)
{
    // ログイン情報を取得する
    LoginPageContext loginPageContext = (LoginPageContext) Resources["loginPageContext"];

    // 認証処理を行う
    var authProxy = new AuthenticationServiceClient();
    authProxy.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(authProxy_LoginCompleted);
    authProxy.LoginAsync(loginPageContext.UserId, loginPageContext.UserPassword, null, false);
}

private void authProxy_LoginCompleted(object sender, LoginCompletedEventArgs e)
{
    if (e.Error != null) throw e.Error; // TODO とりあえずそのまま返却する

    // ログイン結果を判定する
    if (e.Result)
    {
        // ログイン成功
        var userProxy = new UserAccessServiceClient();
        userProxy.GetUserDataCompleted += new EventHandler<GetUserDataCompletedEventArgs>(userProxy_GetUserDataCompleted);
        userProxy.GetUserDataAsync();
    }
    else
    {
        // TODO ログイン失敗
        ChildWindow cw = new ChildWindow();
        cw.Width = 400;
        cw.Height = 100;
        cw.Content = "ログインに失敗しました。";
        cw.Show();
    }
}

private void userProxy_GetUserDataCompleted(object sender, GetUserDataCompletedEventArgs e)
{
    // ユーザ情報を取得する
    UserContainer userContainer = e.Result as UserContainer;

    // ユーザ情報を保持する
    LoginUserContext userContext = (LoginUserContext)Application.Current.Resources["loginUserContext"];
    userContext.LoginDate = DateTime.Now;
    userContext.UserName = userContainer.lastNamek__BackingField + userContainer.firstNamek__BackingField;
    userContext.userContainer = userContainer;

    // 基底画面へ遷移する
    NavigationService.Navigate(new Uri("/Base", UriKind.Relative));
}

めんどくさいので説明は省略します。

以上で、終了です。

ThomasThomas2012/02/18 04:01I went to tons of links bferoe this, what was I thinking?

rmoamyljzgdrmoamyljzgd2012/02/19 17:33CBLouT <a href="http://mcdwkixxzhoe.com/">mcdwkixxzhoe</a>

hwapkecbkjhwapkecbkj2012/02/19 23:49CDGcQo , [url=http://urwxdpeyhwgr.com/]urwxdpeyhwgr[/url], [link=http://senmheftsdll.com/]senmheftsdll[/link], http://bmcegdmdhnth.com/

2010-05-19

SQL Server 2008についてのメモ - インポート、エクスポートについて

| 15:31

今日は、SQL Server 2008についてのメモ。

SQL ServerSQLを実行する方法

まずは、DOSプロンプトで以下のコマンドを実行します。

sqlcmd -S \SQLEXPRESS -d DataBaseName

「\SQLEXPRESS」はインスタンス名で、「DataBaseName」はデータベース名です。

上記のコマンドではlocalhostになっているので、別のサーバに接続するときはホスト名とポートを指定します。

ちなみに、ユーザは統合認証を利用しているので必要ありません。(Windowsのユーザ情報を利用して認証を実施している)

接続に成功したら、SQL文を記述して、goします。

1> select * from project
2> go

てか、goってw

このコマンドってSQLを実行するツールというより、ストアドプロシージャーを実行するツールなんですかね。

まあ、SQL文が実行できればなんでもいいんです。

SQL Serverでのインポートエクスポート

bcpコマンドを利用するそうです。

データをエクスポートするには以下のコマンドを実行します。

bcp "select * from DataBaseName.SchemaName.TableName" queryout Data.dat -T -c -S localhost\SQLEXPRESS

上記コマンドを実行するとData.dat(ファイル名は任意)が作成され、select文の実行結果が書き込まれます。

データのインポート以下の通りです。

bcp DataBaseName.SchemaName.TableName in Data.dat -T -f TableName.xml -S localhost\SQLEXPRESS

エクスポート時に作成したファイルを利用してインポートを実施します。

ちなみに、このインポートではフォーマットファイルを使用いています。

フォーマットファイルを利用するとデータと列のマッピングを行えるので便利です。

フォーマットファイルを作成するコマンドを以下の通りです。

bcp DataBaseName.SchemaName.TableName format nul -T -c -x -f TableName.xml -S localhost\SQLEXPRESS

上記コマンドを実行するとTableName.xml(ファイル名は任意)が作成され、XML形式でテーブル定義が出力されます。

ちなみに、XML以外でも出力できるみたいですがSQL Server独自の形式でDDLではありません。

DDLを作るにはSQL Server Management Studioが必要みたいです。

開発時には単体用、結合用など複数のデーターベースが必要なので、DDLは必須です。

今回はSQL Server Management Studioより、S2JDBC-GENを使ってみました。

理由としては、使い慣れているということと、バージョン管理なども考えられているし、なにより簡単!

ということで、S2JDBC-GENを利用したSQL Serverマイグレーションについては次回にします。

IvanIvan2012/02/18 18:58I guess finding useful, reliable information on the itnerent isn't hopeless after all.

rpbzxpkrpbzxpk2012/02/19 19:42S3NbHa <a href="http://ivsiqwkzwwjs.com/">ivsiqwkzwwjs</a>

hazcekphazcekp2012/02/20 01:58U6PFjv , [url=http://psyklsxgvsph.com/]psyklsxgvsph[/url], [link=http://xrxztlryelad.com/]xrxztlryelad[/link], http://wornnbmmythm.com/