Dynamics CRM 2011は後方互換性のためCRM4.0のエンドポイント ( /mscrmservices/2007/crmservice.asmx ) を使用するCrmService を使用できます。AD認証の場合は滞りなく使えます。IFD認証の場合どうなのよと思って、試してみました。結果から先に記述すると、DiscoveryService にアクセスした時点で 下図のように "HTTP ステータス 401: Unauthorized エラーで要求が失敗しました" が発生し動作させることができませんでした。
ちなみに、下記フォーラムの内容によると、Unauthorizedエラーは仕様通りで、一度ブラウザでフォーム認証されていれば動作するという回答をサポートから受けたようです。ってことはコンソールアプリでCrmServiceを使用している場合、IFD構成では、後方互換性が担保されないってことだと思われます。
Cannot access CRM 4.0 Discovery services on a CRM 2011 installation
http://social.microsoft.com/Forums/en-US/crmdeployment/thread/d92924d8-5982-4a11-ac66-602feb4542c8
1. 検証プログラム
参考までに、検証に使用したプログラムを掲載します。最初に、CrmService と DiscoveryService 用のプロキシを作成します。以下ではIFD用のURLでアクセスすると、wsdlを取得しプロキシを作成できなかったので、AD認証用のURLでプロキシを作成します。
コンソールプログラムを作成し、プロジェクトを右クリック→サービス参照の追加を行います。
サービス参照の追加画面が表示されます。下部の詳細設定ボタンをクリックします。
サービス参照設定ダイアログが表示されます。互換性セクションの Web 参照の追加 ボタンをクリックします。
Web 参照の追加画面が表示されます。 URL に CRM4.0 用の CrmServiceWsdl.aspx の URL を入力し、右の矢印ボタンをクリックします。本例では、http://localhost/mscrmservices/2007/CrmServiceWsdl.aspx?wsdl=dyn と入力しています。環境に合わせて変更してください。
Webサービスの検索に成功したら、 Web 参照名に適当な名前(本例では Crm4Sdk) を入力して 参照の追加ボタンをクリックします。
同様の手順で CrmDiscoveryService のプロキシを作成します。 URLは本例では、 http://localhost/MSCRMServices/2007/AD/CrmDiscoveryService.asmx?wsdl としています。環境によってホスト名などのURLを変更してください。IFDの場合 本来、パスの /AD/ の部分は /SPLA/ なのですが、wsdlを取得できなかったので、 AD認証用のURLを使用してプロキシを作成しています。
以上でプロキシの準備ができました。
あとは、Program.cs を次のように変更して実行します。プログラムは CrmDiscoveryService からチケットを取得し、作成したチケットを利用して CrmService のインスタンスを作成します。そのあとは WhoAmIRequest を呼び出しています。といっても、DiscoveryService にアクセスした時点でエラーになってしまうのですが。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using LegacyCrmSeviceIfdSample.Crm4Sdk; using LegacyCrmSeviceIfdSample.Crm4Sdk1; using System.Security.Cryptography.X509Certificates; using System.Net.Security; namespace LegacyCrmSeviceIfdSample { class Program { static void Main(string[] args) { // 自己証明書対応用。証明書に問題があっても続行するようにする。 System.Net.ServicePointManager.ServerCertificateValidationCallback += RemoteCertValidation; CrmService service = GetService("https://dyn.dcrm.local", "dyn", "dcrm\\testuser", "password"); WhoAmIRequest request = new WhoAmIRequest(); WhoAmIResponse response = service.Execute(request) as WhoAmIResponse; Console.WriteLine(response.UserId); } static CrmService GetService(string serverurl, string organizationName, string username, string password) { UriBuilder uriBuilder = new UriBuilder(serverurl); uriBuilder.Path = "/MSCRMServices/2007/SPLA/CrmDiscoveryService.asmx"; CrmDiscoveryService disco = new CrmDiscoveryService(); disco.Url = uriBuilder.Uri.ToString(); disco.Credentials = System.Net.CredentialCache.DefaultCredentials; disco.UseDefaultCredentials = true; RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest(); orgRequest.UserId = username; orgRequest.Password = password; RetrieveOrganizationsResponse orgResponse = (RetrieveOrganizationsResponse)disco.Execute(orgRequest); bool found = false; string serviceUrl = string.Empty; foreach (OrganizationDetail orgdetail in orgResponse.OrganizationDetails) { if (orgdetail.OrganizationName == organizationName) { found = true; serviceUrl = orgdetail.CrmServiceUrl; } } if (found == false) return null; RetrieveCrmTicketRequest ticketRequest = new RetrieveCrmTicketRequest(); ticketRequest.OrganizationName = organizationName; ticketRequest.UserId = username; ticketRequest.Password = password; RetrieveCrmTicketResponse ticketResponse = (RetrieveCrmTicketResponse)disco.Execute(ticketRequest); CrmAuthenticationToken token = new CrmAuthenticationToken(); token.AuthenticationType = 2; // IFD, ADの場合 0 token.OrganizationName = organizationName; token.CrmTicket = ticketResponse.CrmTicket; UriBuilder bi = new UriBuilder(serverurl); bi.Path = "/mscrmservices/2007/crmservice.asmx"; CrmService service = new CrmService(); //service.Credentials = new System.Net.NetworkCredential(username, password); service.Credentials = System.Net.CredentialCache.DefaultCredentials; service.CrmAuthenticationTokenValue = token; service.UseDefaultCredentials = true; service.Url = bi.Uri.ToString(); return service; } static bool RemoteCertValidation(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) { if (error != SslPolicyErrors.None) { Console.WriteLine("証明書に問題があります。理由:" + chain.ChainStatus[0].StatusInformation); Console.Write("処理を続行しますか? y:続行:"); string input = Console.ReadLine(); if (input.ToLower() == "y") return true; else return false; } return true; } } }
実行すると、 RetrieveOrganizationsResponse = (RetrieveCrmTicketResponse)disco.Execute(ticketRequest); の部分で以下の例外(HTTP ステータス 401: Unauthorized で要求が失敗しました。)が発生します。
2.まとめ
今回の説明は以上です。間違っていたらご指摘お願いします。
個人的には予想通り、CRM2011用のIFD認証では、CRM4.0用のコンソールプログラムはうまく動作しませんでした。プログラムを作成しなおすか、AD認証にするかの変更が必要みたいです。.NET3.5でどうしても動作させる必要がある場合は、 [Dynamics CRM 2011] WSDL Endpoint を使用するコンソールアプリケーション(認証方式はIFDクレーム認証)を作成する の方法で一般的なWCFクライアントを作成して対応する方法もあります。
CRM4のIFD認証を使用するプログラムを作成したので、プログラムが間違っているんじゃないかという懸念もしますが、AD認証の場合は動作したので問題ないはずです。
さんのコメント: さんのコメント: