The decision to write early or late bound code is often a tricky one. I personally think if you are in an environment that you can control, for example you are an inhouse developer for the company that ‘owns’ CRM then early binding makes sense as you can add a step into your development/deployment pipeline that will regenerate an up to date entities file. If you are working say for a reseller who is developing a project for a customer who may get copies of the source code for further development either by yourselves or possibly someone else and you may have no control over the fields etc in the CRM solution then late binding is probably the way to go.
Early binding definitely has its advantages, it makes code much easier to read and make queries easier as you can simply use linq to join tables and get field lists.
All you really need to write early bound code is an entities file. You may decide to call this something else but as long as it is consistent and you update it each time the solution in CRM changes you should be fine.
Generating the file is straightforward.
The actual utility to do this is called CRMSVCUTIL.EXE and is a Dynamics specific version of the SVCUTIL.EXE tool that generates metadata and service model code.
Since V9 this is available when you download, or include the nuget package “Microsoft.CrmSdk.CoreTools” in your solution. If you look in the folder where it has been downloaded which will probably be “\packages\Microsoft.CrmSdk.CoreTools.9.0.3.4\content\bin\coretools” although the version number may change over time, you will see the file CRMSVCUTIL.EXE. This is a command line application and it can be run simply using a batch file like this.
d:
cd\
cd \Projects\MYCRMProject\src\packages\Microsoft.CrmSdk.CoreTools.9.0.3.4\content\bin\coretools
CrmSvcUtil.exe /connectionstring:"url=https://mycrm.crm11.dynamics.com; username=me@dummyuser.com; password=****; Authtype=Office365" /o:"d:\projects\MyCRMProject\src\entities.cs" /serviceContextName:"Datacontext" /n:Crm.Entities
The batch file simply navigates to the directory where the CRMSVCUTIL is actually stored.
The /connectionstring: parameter is the connection string to connect to your version of Dynamics, in this case I am assuming you are using an on-line version.
The /o: parameter specifies where the file will actually be generated. In this case I am generating it so that it can be included in my project. Once it is added to the project I can regenerate the file as many times as I want.
The /serviceContextName: parameter defines the service context I can use to access the data. This will provide me with a context for running Linq queries etc.
The /n: parameter supplies the Namespace that I want the data to be generated in. This is optional and if none is specified it will be created as global. If you generate this with a separate namespace it can be included in your project with a using statement.
There are more options available in CRMSVCUTIL.EXE but the ones specified above are enough to get going quickly. Run the utility without and options to see the full list available.
Once the file has been generated add it to your C# project in visual studio, include a using Crm.Entities statement (or whatever namespace you are using) to the top of your code and you can reference entities immediately. You will also need to enable the early bound types by adding the following to your Organization Service connection.
<OrganizationService>.EnableProxyTypes();
For example:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
CrmServiceClient conn = new CrmServiceClient(CrmServiceConnectionString);
OrganizationServiceProxy orgServiceProxy = conn.OrganizationServiceProxy;
var _crmService = (IOrganizationService)orgServiceProxy;
var _crmServiceContext = new OrganizationServiceContext(_crmService);
orgServiceProxy.EnableProxyTypes();
Accessing the entities can be done like:
Contact contact = new Contact;
contact.firstname="firstname";
contact.lastname="lastname";
service.Create(contact);
Instead of
Entity contact=new Entity("contact");
contact.AddAttribute("firstname","value");
contact.AddAttribute("lastname","value");
service.Create("contact");
A DataContext can be created with the following code:
DataContext myContext=new DataContext(orgServiceProxy);
This allows Linq queries like this to be executed
var mylist= (from s in context.SalesOrderDetailSet
join p in context.ProductSet on s.ProductId equals new EntityReference(SalesOrderDetail.EntityLogicalName, p.Id)
where s.SalesOrderId == new EntityReference(SalesOrder.EntityLogicalName, orderId)
where p.ProductTypeCode.Value == (int)ProductType.Course
select s).ToList();
This makes the code much easier to read, but the decision on whether the code should be early or late bound should be done on a project by project basis.