locked
SharePoint2010で外部のデータベースを利用するには? (BDCは利用しない) RRS feed

  • 質問

  • SharePoint 2010 にて、イベントレシーバーを利用してドキュメントライブラリにファイルがが追加された時(ItemAdded)に、外部のデータベースをキー参照して、取得した値をプロパティ値として自動入力をする仕組みを実現しようと思っています。

    ところが、データベース参照のためにSqlConnectionのインスタンス作成時にエラーメッセージが表示されてしまい、処理を行うことができません。
    開発経験が浅いため手探りで試行錯誤しているところですが、どなたかご教授いただけないでしょうか?

    ■エラーメッセージ
    TypeInitializationException はユーザーコードによってハンドルされませんでした。
    'System.Data.SqlClient.SqlConnection' のタイプ初期化子が例外をスローしました。

    ■ソースコード
    using System;
    using System.Security.Permissions;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Security;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.Workflow;
    using System.Collections.Generic;
    using System.Text;
    using System.Data.SqlClient;

    namespace TestDocLib.TestEventReceiver1
    {
        public class TestEventReceiver1 : SPItemEventReceiver
        {
            public override void ItemAdded(SPItemEventProperties properties)
            {
                SqlConnection conn = new SqlConnection();    // ← ★ここでエラーが発生
                conn.ConnectionString = @"接続文字列";

                conn.Open();

                conn.Close();

                properties.ListItem.Update();
                base.ItemAdded(properties);
            }
        }
    }

    色々と基礎が足りないかもしれませんが、よろしくお願いします。

    2014年8月15日 4:20

回答

  • サンドボックスソリューションとしての認識がなくて申し訳ありません。

    サンドボックスソリューションであれば、様々な制約があるため、実現しようとしている実装は難しいかもしれないですね。

    # 一応、サンドボックスソリューションの制限ページを貼っておきます。
    http://msdn.microsoft.com/ja-jp/library/gg615454(v=office.14).aspx

    実現方法として思いつくのは、記述頂いた通り、データベースのテーブルと外部接続させたリストを参照するか、データベースのテーブルを参照するWebサービスを作っておいて、そのWebサービスを呼び出すか、になるかと思います。

    • 回答としてマーク magutan 2014年8月18日 1:39
    2014年8月18日 1:17
  • SurferOnWww さん
    たけさと さん

    当質問について、実現したいことができるようになりましたので、情報共有のために追記しておきます。
    (…といっても、ケアレスミスというか、ちょっとお恥ずかしい話です)

    今回の件は、サンドボックスソリューションで実施しているために実現ができなかったようです。
    つまり、ファームソリューションでは実現できました。

    元々、サンドボックスソリューションにこだわっていることはなかったのですが、改めて今までのやりとりを見直して、「サンドボックスソリューションで制限があるならば…あれ?そもそもなんでサンドボックスソリューションにこだわってたんだ?」と思い、ファームソリューションで同じコードを書いて実現することができました。

    もっとも、展開方法はサンドボックスソリューションと異なってPowerShell等を使うことになりましたが、psファイルを用意しておけば難しい展開作業ではありませんし、何よりも実現できなかったことができるようになりましたので、全然気にしていません。

    最終的に無事に自己完結しましたが、今回の質問にお答えしてくださったお二人の返信内容に色々とヒントをいただきました。
    改めまして、ありがとうございました。


    • 回答としてマーク magutan 2014年8月18日 10:21
    • 編集済み magutan 2014年8月19日 0:41 誤字修正
    2014年8月18日 10:20

すべての返信

  • ググって調べた限りですが、構成ファイルのエラーが原因としては一番疑わしいように思えます。

    以下のようにして原因を調査し、解決したという記事があります。ご参考まで。

    SqlConnection error
    http://social.msdn.microsoft.com/Forums/en-US/b885fe14-e76b-43ed-8d41-73c5648da78c/sqlconnection-error?forum=adodotnetdataproviders

    ハズレだったらすみません。

    2014年8月15日 4:49
  • SurferOnWww さん

    返信ありがとうございます。

    参考のURLを拝見しましたが、英語というのもあって理解が難しかったのですが、Configに相当するファイルが必要(?)という内容でしょうか。
    内容の把握がいまいち理解できないところもあり、ハズレかどうかもわかりませんでした。
    また、Configファイルを定義するとしても、定義方法を理解するに至りませんでした。
    (申し訳ないです…)

    2014年8月15日 6:45
  • SharePoint のことは良く知りませんが、以下のページの「IIS と ASP.NET 構成」のセクションによると、構成ファイルは ASP.NET と同様 machine.config, web.config, applicationhost.config とのことです。

    ASP.NET アプリケーションとしての Microsoft SharePoint Foundation
    http://msdn.microsoft.com/ja-jp/library/ee537834(v=office.14).aspx


    ただ、ASP.NET 開発とは異なる SharePoint の特殊事情もあるようで、そのあたりの詳しいことは自分には分かりません。

    ASP.NET と SharePoint: Web.config ファイルを変更する
    http://msdn.microsoft.com/ja-jp/library/ff407245(v=office.14).aspx

    お役に立てずすみませんが、そのあたりに詳しい他の回答者の方の回答をお待ちください。

    2014年8月15日 7:42
  • # SharePoint 2010のイベントレシーバ前提で回答致します。

    イベントレシーバが、アクションを起こしたユーザーの資格情報で実行されているため、アクションを起こしたユーザーの資格情報では、SurferOnWwwさんにご紹介頂いた構成ファイルにアクセスできない事が原因で、エラーになっているものと思われます。

    イベントレシーバ内で、サーバーのローカルリソースを利用したり、外部接続したい場合には権限昇格を使うのがSharePointの定石です。

    public override void ItemAdded(SPItemEventProperties properties)
    {
        SPSecurity.RunWithElevatedPrivileges(delegate(){
          // ここに権限昇格させて実行したいコードを記述。
        });
    }

    また、別件ですが、記述頂いたコードはListItem.Update()で再度ItemAddedイベントが発生し、ループしてしまうため、以下の記述で挟む必要があります。

    this.EventFiringEnabled = false;
    // ここで自分自身のアップデート処理を記述。
    this.EventFiringEnabled = true

    2014年8月15日 8:52
  • SurferOnWww さん
    たけさと さん

    お二人とも、返信ありがとうございます。とてもためになる情報を提供していただいて勉強になります。

    たけさとさんの情報を参考に色々とやってみましたが、どうやらSPSecurity自体、使うことができないようです。
    (備忘録も兼ねて長い内容になりますが…詳細は後述)

    まず次のようにSPSecurityに関するコードの改修を行ってみましたが、RunWithElevatedPrivilegesのコードは実行されず、ブロック内で記載した出力ウィンドウへのメッセージ処理はされませんでした。

    ■ソースコード①
    using System;
    using System.Security.Permissions;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Security;  // ←追加
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.Workflow;
    using System.Collections.Generic;
    using System.Text;
    using System.Data.SqlClient;

    namespace TestDocLib.TestEventReceiver1
     {
         public class TestEventReceiver1 : SPItemEventReceiver
         {
             public override void ItemAdded(SPItemEventProperties properties)
             {
                SPSecurity.RunWithElevatedPrivileges(delegate()  // ←追加
                {
                    System.Diagnostics.Trace.WriteLine("処理実行されました");  // ←★出力ウィンドウに表示されない(処理されない?)
                });
    …(略)…

    次に、RunWithElevatedPrivilegesで行われる内容をメソッドで出して、CodeToRunElevatedコンストラクタを使用してみましたが、こちらも同じくメッセージ処理はされませんでした。

    ■ソースコード②
    …(略)…
    namespace TestDocLib.TestEventReceiver1
     {
         public class TestEventReceiver1 : SPItemEventReceiver
         {
             public override void ItemAdded(SPItemEventProperties properties)
             {
                SPSecurity.CodeToRunElevated cMethod = new SPSecurity.CodeToRunElevated(TestMethod);  // ←追加
                SPSecurity.RunWithElevatedPrivileges(cMethod);  // ←変更
             }

             public void TestMethod()
             {
                System.Diagnostics.Trace.WriteLine("処理実行されました");  // ←★出力ウィンドウに表示されない(処理されない?)
             }
    …(略)…

    そして、色々と調べてみたところ、MSDNマガジンに今回の件と関係がありそうな記事を見つけました。

    ■SharePoint 2010 でサンドボックス ソリューションを開発、展開、および監視する
    http://msdn.microsoft.com/ja-jp/magazine/ee335711.aspx

    この記事の図6の少し下あたりに「もう 1 つはサンドボックス内でブロックされる例で、SPSecurity を操作します」というくだりから読んでいくと、SharePoint APIの関連によりSPSecurityをサンドボックスで処理できないようなことが載っていました。

    ということは、今回のケースは実現ができず、外部データを定義して…といった他の手法しかないのでしょうか。
    外部データ設定の手間や操作ミスのリスクをなくす、複数ファイルをアップロードする時にデータベースを参照してプロパティの自動入力を行う、といったことを目論んでいたので、実現できないとなると結構ショックです…。

    2014年8月16日 8:19
  • サンドボックスソリューションとしての認識がなくて申し訳ありません。

    サンドボックスソリューションであれば、様々な制約があるため、実現しようとしている実装は難しいかもしれないですね。

    # 一応、サンドボックスソリューションの制限ページを貼っておきます。
    http://msdn.microsoft.com/ja-jp/library/gg615454(v=office.14).aspx

    実現方法として思いつくのは、記述頂いた通り、データベースのテーブルと外部接続させたリストを参照するか、データベースのテーブルを参照するWebサービスを作っておいて、そのWebサービスを呼び出すか、になるかと思います。

    • 回答としてマーク magutan 2014年8月18日 1:39
    2014年8月18日 1:17
  • たけさと さん

    私も色々と手を尽くしてみましたが、やはり難しそうなんですね。
    色々とご教授いただきありがとうございました。

    前に返信していただいた、
    > イベントレシーバ内で、サーバーのローカルリソースを利用したり、外部接続したい場合には権限昇格を使うのがSharePointの定石です。

    については目からウロコな気分で、奥が深いなぁと感じました。
    思ってみれば、SharePointDesignerで権限昇格によるワークフロー操作などもあったので、開発の場面でもちょっと特別なことを行うには権限が関連するという考え方が自分にプラスとなりました。
    今後、色々と考察する中で思い通りにいかない時に出会ったら、権限についての要素も考慮するようにします。

    今回の件は他のアプローチを考えてみます。
    ありがとうございました。
    2014年8月18日 1:39
  • SurferOnWww さん
    たけさと さん

    当質問について、実現したいことができるようになりましたので、情報共有のために追記しておきます。
    (…といっても、ケアレスミスというか、ちょっとお恥ずかしい話です)

    今回の件は、サンドボックスソリューションで実施しているために実現ができなかったようです。
    つまり、ファームソリューションでは実現できました。

    元々、サンドボックスソリューションにこだわっていることはなかったのですが、改めて今までのやりとりを見直して、「サンドボックスソリューションで制限があるならば…あれ?そもそもなんでサンドボックスソリューションにこだわってたんだ?」と思い、ファームソリューションで同じコードを書いて実現することができました。

    もっとも、展開方法はサンドボックスソリューションと異なってPowerShell等を使うことになりましたが、psファイルを用意しておけば難しい展開作業ではありませんし、何よりも実現できなかったことができるようになりましたので、全然気にしていません。

    最終的に無事に自己完結しましたが、今回の質問にお答えしてくださったお二人の返信内容に色々とヒントをいただきました。
    改めまして、ありがとうございました。


    • 回答としてマーク magutan 2014年8月18日 10:21
    • 編集済み magutan 2014年8月19日 0:41 誤字修正
    2014年8月18日 10:20