Tuesday, May 15, 2012

IOrganizationService Overview

Overview


The IOrganizationService is the main Web Service that provides methods for accessing and manipulating data in your Organization.

There are two main ways to consume the IOrganizationService:

  • Via the Microsoft.Xrm.Sdk and Microsoft.Xrm.Sdk.Proxy dll's 
  • Referencing the Organization WCF Service directly through it's Service Reference.

Microsoft.Xrm.Sdk dll's


The Microsoft.Xrm.Sdk dll's are the main and recommended method for interacting with the IOrganizationService. To do this  Visual Studio add references to the following assemblies located in the CRM SDK <installdir>/SDK/bin folder:

In addition you will need to add the following .Net assemblies:
  • System.Runtime.Serialization.dll
  • System.ServiceModel.dll

Once added to your Visual Studio project you're ready to start developing code to communicate with CRM via the IOrganizationService.


Instantiating IOrganizationService


Via Microsft.Crm.SDK

When invoking the IOrganizationService via the Microsoft.Xrm.Sdk dll's the IOrganizationService is generated by an OrganizationServiceProxy instance.  The OrganizationProxy is responsible for abstracting the communication with the underlying SOAP WCF service as shown below:


using( OrganizationServiceProxy _Service = new OrganizationServiceProxy(OrganizationUri
                                                                       , null
                                                                       , credentials
                                                                       , null))
{   
   IOrganizationService _iOrganizationService = (IOrganizationService)_Service;
}


In the code sample above an OrganizationServiceProxy is wrapped in a using statement to ensure that it is properly disposed of as it implements IDisposable(). The OrganizationServiceProxy constructor has 5 overloads accepting parameters for defining Federation Server URI's and Device Id's for Windows Live Single Sign On. These will be dicussed in detail in a different post and are set to NULL for the sample code above.  


Integrated Windows Authentication

To authenticate against the OrganizationService using Integrated Authentication a new instance of ClientCredentials should be instantiated and assigned the DefaultNetworkCredentials from the CredentialCache which resides in the System.Net assembly.

ClientCredentials credentials = new ClientCredentials();
credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
OrganizationServiceProxy _Service = new OrganizationServiceProxy(OrganizationUri, null, credentials, null);


Active Directory Authentication

To authenticate using Active Directory Authentication add a reference to the Microsoft.Xrm.Sdk.Client assembly and declare a new instance of AuthenticationCredentials and instantiate the ClientCredentials.Windows.ClientCredential property as follows:

AuthenticationCredentials creds = new AuthenticationCredentials();
creds.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(_userName 
                                                                                    , _password
                                                                                    , domain);
OrganizationServiceProxy _Service = new OrganizationServiceProxy(OrganizationUri
                                                                 ,null
                                                                 ,creds.ClientCredentials.ClientCredentials
                                                                 ,null);



Windows Live Id (Online)

To authenticate using Windows Live Id you need to register your machine using DeviceRegistration.exe to create a Device Id and Password. DeviceRegistration.exe is located in the SDK\tools\deviceregistration folder of your deployed CRM 2011 SDK.

The following code snippet shows how to assign the device id, username and password to an AuthenticationCredentials instance for instantiating the IOrganizationServiceProxy class with:

authCredentials.ClientCredentials.UserName.UserName = _userName;
authCredentials.ClientCredentials.UserName.Password = _password;
authCredentials.SupportingCredentials = new AuthenticationCredentials();
authCredentials.SupportingCredentials.ClientCredentials = Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();

OrganizationServiceProxy _Service = new OrganizationServiceProxy(OrganizationUri
                                                                 ,null

                                                                 ,creds.ClientCredentials.ClientCredentials
                                                                 , null);


Executing Service Requests

The following demonstrates how to execute a simple service request to retrieve a list of Accounts using a QueryExpression:

private static void ExecuteGetAccounts_QueryExpression(IOrganizationService service)
{


     QueryExpression query = new QueryExpression("account");
     query.ColumnSet = new ColumnSet();
     query.ColumnSet.AllColumns = true;

     EntityCollection accounts = service.RetrieveMultiple(query);
     
     foreach (Entity entity in accounts.Entities)
     {
        Console.WriteLine("Name: {0}", entity["name"]);
     }
}



The following demonstrates how to execute a simple service request to retrieve a list of Accounts using FetchXML:

private static void ExecuteGetAccounts_FetchXML(IOrganizationService service)
{
    Console.WriteLine("Executing Fetch XML Query");

    string fetchAccount = @"
                          <fetch mapping='logical'>
                             <entity name='account'>
                                <attribute name='accountid'/>
                                   <attribute name='name'/>
                                </entity>
                             </fetch> ";


    EntityCollection result = service.RetrieveMultiple(new FetchExpression(fetchAccount));
    foreach (var entity in result.Entities)
    {
       Console.WriteLine("Name: {0}", entity["name"]);
    }
}



Via SOAP

When invoking the IOgranizationService directly via the WCF Service endpoint, an OrganizationServiceClient object is used. The OrganizationServiceClient constructor requires details about the WCF binding which can either be specified programatically or within the Applicaiton or Web.Configuration file of your solution. Daniel Cai's blog details how to programatically configure the CRM WCF Service bindings without a configuration file.


Configuring SOAP Access

The following demonstrates how to instantiate OrganizationServiceClient and return IOrganizationService via the WCF SOAP endpoint.
  • Add the CRM WCF SOAP endpoint to your solution as a Service Reference:
Visual Studio - Add Organization Service Reference


Adding the Service Reference will automatically generate the configuration bindings in your solution app / web.config file:

<system.serviceModel>
    <bindings>
      <customBinding>
        <binding name="CustomBinding_IOrganizationService">
         
             <security defaultAlgorithmSuite="Default" authenticationMode="SspiNegotiated" requireDerivedKeys="true" securityHeaderLayout="Strict" 
            includeTimestamp="true" keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"
            messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
            requireSecurityContextCancellation="true" requireSignatureConfirmation="false">
            <localClientSettings cacheCookies="true" detectReplays="true"
              replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
              replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
              sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
              timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
            <localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00"
              maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
              negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
              sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
              reconnectTransportOnFailure="true" maxPendingSessions="128"
              maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
            <secureConversationBootstrap />
          </security>
          <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
            messageVersion="Default" writeEncoding="utf-8">
            <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          </textMessageEncoding>
          <httpTransport manualAddressing="false" maxBufferPoolSize="524288"
            maxReceivedMessageSize="999999" allowCookies="false" authenticationScheme="Anonymous"
            bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
            keepAliveEnabled="true" maxBufferSize="999999" proxyAuthenticationScheme="Anonymous"
            realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
            useDefaultWebProxy="true" />
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="
http://<SERVER>/<ORGANIZATION>/XRMServices/2011/Organization.svc"
        binding="customBinding" bindingConfiguration="CustomBinding_IOrganizationService"
        contract="CRMOrgService.IOrganizationService" name="CustomBinding_IOrganizationService">
      </endpoint>
    </client>

</system.serviceModel>

The default authentication scheme is Anonymous as highlighted above. To implement Integrated Authentication change the authenticaitonScheme and proxyAuthenticationScheme nodes to "Negotiate"

Note: The Integrated Authentication attribute setting for authenticationScheme and proxyAuthenticationScheme is not a valid setting for http and https transport bindings. The following defines the permitted HttpTransport and HttpsTransport attributes and elements for a WCF binding.


Executing SOAP Service Requests

One of the main advantages of using the SOAP endpoint over the Microsoft.Xrm.SDK dlls is that it exposes the following additional methods for Asynchronous execution:

  • Begin / End Associate
  • Begin / End Create
  • Begin / End Update
  • Begin / End Delete
  • Begin / End Disassociate
  • Begin / End Execute
  • Begin / End RetrieveMultiple


  • The following demonstrates how to instantiate an OrganizationServiceClient with the binding configuration specified above and execute an asynchronous service request.

    OrganizationServiceClient client = new OrganizationServiceClient("CustomBinding_IOrganizationService"); 

    private static void Begin_AsyncExection(ClientCredentials credentials)
    {
        QueryExpression query = new
    QueryExpression();
        query.EntityName = "account";
        query.ColumnSet = new ColumnSet();
        query.ColumnSet.Columns = new string[] { "name" };
        service.BeginRetrieveMultiple(query, Async_Callback, service);

    }

    private static void Async_Callback(IAsyncResult result)
    {
        EntityCollection response = ((IOrganizationService)result.AsyncState).EndRetrieveMultiple(result);

        foreach (Entity entity in response.Entities)
        {
            for (int i = 0; i < entity.Attributes.Count; i++)
            {
                KeyValuePairOfstringanyType attribute = entity.Attributes[i];

                Console.WriteLine(attribute.value);
            }
        }

    }


    Additional Reading


    The Microsoft Patterns & Practices WCF Security guide goes into great detail the different WCF binding configurations and can be found here.

    No comments:

    Post a Comment