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で行っています。