What it does
The .NET client for Dataverse business data and table definitions. You connect through IOrganizationService, build a typed request object such as CreateRequest or RetrieveMultipleRequest, execute it, and get a matching response back. Microsoft's documentation is blunt about its position: the organization service is what defines the platform, and the Web API is a RESTful presentation over the top of it.
Key facts
- Two NuGet packages.
Microsoft.CrmSdk.CoreAssembliesfor .NET Framework only — this is what plug-ins and custom workflow activities need.Microsoft.PowerPlatform.Dataverse.Clientfor .NET Framework or .NET, and that's the one for new client applications. - Two implementations of
IOrganizationService:ServiceClientand the olderCrmServiceClient. UseServiceClientfor anything new; it uses MSAL whereCrmServiceClientstill uses ADAL, and it has features the older class doesn't. The APIs are close enough that conversion is straightforward. - Every operation is a message with a name, and those names are what the event framework binds extensions to.
Create,Retrieve,RetrieveMultiple,Update,Delete,Associate,Disassociateplus the specialised ones and anything a custom API adds. ServiceClientandCrmServiceClienthandle service protection 429s for you, pausing and resending after theRetry-Afterduration. Versions of Xrm.Tooling after 9.0.2.16 (May 2019) do this automatically.- The 2011 SOAP endpoint is deprecated. Microsoft has said the SDK assemblies will be updated so code keeps working after the endpoint is removed, with new assemblies available before removal. The Web API uses a different endpoint and is unaffected.
OrganizationServiceProxyis deprecated. Replace it withServiceClient.- Default request timeout is four minutes on
ServiceClientand two minutes onCrmServiceClient, settable viaServiceClient.MaxConnectionTimeout. - Early-bound classes are generated with
pac modelbuilder build, including request and response classes for custom APIs.
When to use / skip
It's not optional for plug-ins and custom workflow activities — that code must be .NET Framework against the SDK, full stop. For standalone integrations it wins when you want strongly typed code, when you want ExecuteTransaction or ExecuteMultiple without hand-rolling multipart payloads, and when the team is a .NET team and the tooling pays for itself. It loses when the payload size matters, when you don't want a NuGet dependency, or when the caller isn't .NET at all. For a straightforward data integration on a modern stack, the Web API's smaller JSON payloads and lack of client dependency usually make it the better default.
Configuration decisions
- Which package, which is really a decision about whether the code will ever run inside the sandbox.
- Connection string authentication type —
ClientSecret,Certificate, or an interactive user flow — and where the credential is stored. - Whether to generate early-bound classes and check them in, or work late-bound with string keys. Early-bound catches schema drift at compile time; late-bound survives schema changes without regeneration.
- Whether to reuse a single
ServiceClientinstance with cloning for parallelism, or create per-thread instances. - Request timeout, and whether raising it is actually the right fix or whether the batch is simply too large.
Gotchas
Microsoft.CrmSdk.CoreAssembliestargets .NET Framework only. Referencing it from a .NET 8 project compiles further than you'd hope and then fails somewhere inconvenient.- Early-bound classes go stale silently. A column rename in a solution and a class file that wasn't regenerated is a runtime error dressed up as a compile-time success.
- Connection string authentication with a username and password is documented but Microsoft explicitly recommends against it and steers you towards managed identities or app credentials. Use it in a demo, never in delivery.
- Raising
MaxConnectionTimeoutto make a bulk operation stop failing usually just moves the failure. Microsoft's own advice is to send fewer records first. - Bulk operation messages such as
CreateMultiplearen't supported inside plug-in code, and neither are batch request types. That constraint bites when someone tries to be clever in a sandbox. - Requests originating inside a plug-in bypass service protection limits entirely, so code that behaves impeccably in the sandbox can hammer the platform when the same class is reused in a console app.
Consultant notes
- If you inherit a codebase on
OrganizationServiceProxyorCrmServiceClient, plan the move toServiceClientas a small dedicated piece of work rather than folding it into a feature. It's mechanical, and it's much worse when it's urgent. - The SOAP endpoint deprecation is a genuine roadmap item to raise with clients running old custom integrations, without dramatising it — the assemblies will be updated first, but somebody has to redeploy them.
- Set the client's expectation that plug-in code is .NET Framework and will stay that way. Developers who've only worked in modern .NET find this genuinely surprising.
- For a new integration on a client's own infrastructure, ask whether .NET is actually the requirement or just the habit. The Web API is often the lower-maintenance answer.
Worth revisiting when Microsoft announces the updated SDK assemblies for the SOAP endpoint removal.