Dynamics CRM では、 CRMインストールフォルダのISV フォルダに、カスタムページを作成することができます。ISVフォルダにアプリケーション用のフォルダを作成し、そのフォルダ配下にASPXのWebページを配置します。
今回のアプリでは、AD用のUrlとIFD用のUrlのどちらでもうまく動作するようにサイトマップに登録します。また、Rollup2 以降でサポートされる方法でdllファイルをデプロイします。つまり、ISV/アプリケーションフォルダ/bin フォルダにdllをデプロイします。
動作確認
- Windows 2003 Enterprise Edition全部入り完了。 Dynamics CRM 4.0 には Rollup 5 が適用されています。
- 開発環境:Visual Studio 2008 Professional
- .NET 3.5
- クライアント:IE6, IE7
1. Crm SDK アセンブリをパブリックフォルダに登録する
今後の開発作業を容易にするために、SDK に付属するアセンブリ microsoft.crm.sdk.dll と microsoft.crm.sdktypeproxy.dll をVisual Studio 2008 のパブリックアセンブリフォルダに格納します。今回の作業は必須ではないですが、このフォルダにdllを保存すると、Visual Studio のソリューションで参照の追加時に参照の追加ダイアログの.NET のタブにアセンブリが表示されるようになります。
パブリックフォルダは、Visual Studio 2008 を標準のパスにインストールした場合、以下のパスになります。このパスに、CrmのSDKに付属する、microsoft.crm.sdk.dll と microsoft.crm.sdktypeproxy.dll をコピーします。
C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies
パブリックアセンブリフォルダにdllをコピーすると、参照の追加時に、.NETタブにdllが表示されるようになります(下図参照)。
2. 今回作成するアプリ
今回はログインしているユーザの、crm上の情報と、ad上の情報を比較して表示するカスタムページを作成します。このページは、IFD,AD認証した場合に動作するようにします。
下図が完成図です。以下はAD認証により、ログインしたユーザの情報をカスタムアプリケーションで表示した図です。
以下は、IFD認証でログインしたユーザの情報をカスタムアプリケーションで表示した図です。
3. カスタムWebアプリケーションの作成
3.1 プロジェクトの作成
Visual Studio を起動して、webアプリケーションプロジェクトを作成します。今回は、WhoAmIという名前で作成しました。既定で作成されるWeb.config の認証 <authentication mode="Windows" /> は、使用しないので、コメントにしておいてください。
3.2 dll参照の追加
参照の追加で、microsoft.crm.sdk.dll と microsoft.crm.sdktypeproxy.dll を追加します。Visual Studio のパブリックアセンブリフォルダにdllを格納していない場合は、参照の追加ダイアログの参照タブで直接dllを指定します。 今回のアプリはActive Directory に接続するので、System.DirectoryServices.AccountManagement の参照も追加します。
3.3 ASPXの作成
webアプリケーションを作成したときに既定で作成されるDefault.aspx を次のように編集します。ASPXで特に注意していただきたいのが、ASPXの先頭に@Assembly ディレクティブを使用していることです。コードビハインドが格納されるdll名を指定します。この記述を含めることで、Rollup 2 以降でサポートされるようになった、ISV配下のbinフォルダに各アプリケーション用のアセンブリを格納することが可能になります。Rollup2より前は、CrmのインストールルートのbinフォルダがGACにしか、拡張アプリケーションのdllを格納する方法がありませんでした。
dllをCRMのインストールルートのbinフォルダやGACにデプロイする場合は、@Assemblyディレクティブは必要ないので注意して下さい。
<%@ Assembly Name="WhoAmI" %> <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WhoAmI._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>無題のページ</title> <link href="style.css" rel="stylesheet" type="text/css" /> </head> <body> <form id="form1" runat="server"> <div> <table style="width:100%;border-width:2px;" cellspacing="2px" cellpadding="2px"> <tr class="header"> <td> </td> <td> CRM情報</td> <td> AD情報</td> </tr> <tr> <td> せい</td> <td> <asp:Literal ID="lblCrmLast" runat="server"></asp:Literal></td> <td> <asp:Literal ID="lblADLast" runat="server"></asp:Literal></td> </tr> <tr> <td> めい</td> <td> <asp:Literal ID="lblCrmFirst" runat="server"></asp:Literal></td> <td> <asp:Literal ID="lblADFirst" runat="server"></asp:Literal></td> </tr> </table> </div> </form> </body> </html>
コードビハインドファイルは次のようになります。CrmService を作成して、Crmの情報を取得します。また、System.DirectoryServices.AccountManagement 名前空間のクラスを使用してログインしているユーザのAD上の情報を取得しています。
using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using Microsoft.Crm.SdkTypeProxy; using Microsoft.Crm.Sdk; using Microsoft.Crm.Sdk.Query; using System.Net; using System.DirectoryServices.AccountManagement; namespace WhoAmI { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { WhoAmI(); } private void WhoAmI() { using (new CrmImpersonator()) { CrmService service = GetCrmService(Request.QueryString["orgname"], "localhost"); string samaccount = SetCrmInfo(service); SetADInfo(samaccount); } } private string SetCrmInfo(CrmService service) { ColumnSet cols = new ColumnSet(); cols.Attributes.Add("domainname"); cols.Attributes.Add("firstname"); cols.Attributes.Add("lastname"); Guid systemuserGuid = service.CrmAuthenticationTokenValue.CallerId; systemuser su = (systemuser)service.Retrieve(EntityName.systemuser.ToString(), systemuserGuid, cols); lblCrmFirst.Text = su.firstname; lblCrmLast.Text = su.lastname; int pos = su.domainname.IndexOf('\\'); return su.domainname.Substring(pos + 1); } private void SetADInfo(string samAccount) { PrincipalContext ctxt = new PrincipalContext(ContextType.Domain); UserPrincipal user = UserPrincipal.FindByIdentity(ctxt, IdentityType.SamAccountName, samAccount); lblADLast.Text = user.Surname; lblADFirst.Text = user.GivenName; } /// <summary> /// ユーザがIFD認証で認証されても動作するように作成しています。 /// ただし、CrmServiceの認証はAD認証で行われる前提です。 /// CrmService を必ずAD認証とするには、crmサーバをlocalhost /// で参照します。 /// </summary> /// <param name="orgName"></param> /// <param name="host"></param> /// <returns></returns> private CrmService GetCrmService(string orgName, string server) { UriBuilder builder = new UriBuilder("http", server); builder.Path = "/mscrmservices/2007/crmservice.asmx"; if (string.IsNullOrEmpty(orgName)) { // AD認証 URL if (Request.Url.Segments[2].TrimEnd('/').ToLower() == "isv") { orgName = Request.Url.Segments[1].TrimEnd('/').ToLower(); } // IFD認証 URL if (string.IsNullOrEmpty(orgName)) { string url = Request.Url.ToString().ToLower(); int start = url.IndexOf("://") + 3; orgName = url.Substring(start, url.IndexOf(".") - start); } } CrmAuthenticationToken token = null; token = CrmAuthenticationToken.ExtractCrmAuthenticationToken(Context, orgName); token.OrganizationName = orgName; token.AuthenticationType = 0; // 0:AD, 1:IFD // Crmサービス作成 CrmService service = new CrmService(); service.Credentials = System.Net.CredentialCache.DefaultCredentials; service.CrmAuthenticationTokenValue = token; service.Url = builder.ToString(); return service; } } }
3.4 スタイルシートの作成
Webアプリケーション用のスタイルシートを作成します。ソリューションエクスプローラ上のWebアプリケーションプロジェクトを右クリックし、追加→新しい項目 を選択して、スタイルシートを追加します。ファイル名は、style.css とします。
以下が、style.css の内容です。
body { background-color:#EAF3FF; } table { background-color:Silver; } table .header { background-color:Gray; }
3.5 アプリケーションのデプロイ
プログラムをビルドして、エラーがないことを確認したら、アプリケーションをデプロイします。プロジェクトを右クリックし、発行を選択します。
発行先をCRMがインストールされたフォルダ配下の/ISV/WhoAmI フォルダとします。発行が成功すると、WhoAmIフォルダ配下に、aspx とcss ファイル、binフォルダにWhoAmI.dll が作成されます。デプロイが失敗する場合は、iisreset コマンドでIISを再起動してから行ってください。
準備がととのったので、以降で、Dynamics CRM からサイトマップをエクスポートしてカスタムアプリケーションに遷移できるようにします。
4. Dynamics CRM にカスタムアプリケーションへのメニュー追加
今回は、メニューのワークプレースに"私の情報"というメニュー項目を追加します。
4.1 サイトマップのエクスポート
システム管理者やシステムカスタマイザ権限をもつユーザでCRMにログインします。左メニューの設定を選択後、メニューからカスタマイズを選択します。右ペインのカスタマイズのエクスポートを選択します。
カスタマイズのエクスポート画面のビューでクライアント拡張を選択します。リストにサイトマップが表示されるので、サイトマップを選択し、リスト上部のツールバーから選択したカスタマイズのエクスポートをクリックします。エクスポートしたファイルを保存します。
4.2 サイトマップの編集
エクスポートしたzipファイルを展開します。展開されたcustomizations.xml を編集します。Id がMyWork となっているGroup タグがあるので、末尾に、SubAreaタグを挿入します。SubAreaタグにメニューに表示するタイトルと、拡張ページのURLを設定しています。各属性、要素の意味は、SDKを参照してください。編集したファイルはUTF-8 形式で保存してください。
<Group Id="MyWork" ResourceId="Group_MyWork" DescriptionResourceId="My_Work_Description"> <!-- 省略 --> <!-- 以下を追加 --> <SubArea Id="nav_whoami" Url="../../ISV/WhoAmI/Default.aspx" PassParams="1" > <Titles> <Title LCID="1041" Title="私の情報" /> </Titles> </SubArea> </Group>
4.3 サイトマップのインポート
エクスポート時と同様に、システム管理者またはシステムカスタマイザ権限を持つユーザでDynamics にログインします。左メニューの設定→カスタマイズを選択します。右ペインのカスタマイズのインポートを選択します。
カスタマイズのインポート画面が表示されるので、参照ボタンをクリックして、編集したcustomizations.xmlを選択します。アップロードボタンをクリックします。xmlファイルに問題がなければ、リストにサイトマップが表示されます。リストからサイトマップを選択して、リスト上部の選択したカスタマイズのインポートをクリックして、サイトマップをインポートします。
5. 動作確認
ブラウザを一度閉じ、再度、CRMにログインします。インポートが成功していれば、左ペインのワークプレースメニューに私の情報メニュー項目が表示されます。私の情報をクリックすると、カスタムWebアプリケーションに問題がなければ、2. 今回作成するアプリで掲載したような結果が、右ペインに表示されます。
6. まとめ
今回の説明は以上です。問題点、疑問点などありましたらご連絡ください。
今回の拡張アプリケーションと本質的には関係ないのですが、AD認証の場合、URLの先頭に組織名が付与されて、Web.configやスタイルシートがうまく読み込めないという現象があります。今回のサンプルのように../../という相対パスを拡張アプリケーションに付与するとうまく読み込めるようになります。少なくともIE6,7ではですが。
動作確認は、IE6とIE7で行っています。
さんのコメント: さんのコメント: