# Mastering Microsoft Dynamics 365 CE (CRM) Plugins: Context, Target, and IOrganizationService

In this guide, we’ll explore:

* How to use **IPluginExecutionContext** to access context and target entity.
    
* How to use **IOrganizationService** for CRUD operations.
    
* How to run queries using **QueryExpression** and **FetchXML** (with advanced examples).
    
* How to execute special requests using the service.
    
* Practical **use cases** where each technique is applied.
    

Whether you’re starting with plugins or looking to refine your expertise, this blog will serve as a comprehensive reference.

## Understanding Context and Target

When a plugin executes, the platform provides important runtime information through the **IPluginExecutionContext**. This includes details such as:

* The message (e.g., Create, Update, Delete).
    
* The primary entity name.
    
* The stage in the pipeline (PreValidation, PreOperation, PostOperation).
    
* Input and output parameters.
    

The most important input parameter is often the **Target**, which represents the record that triggered the event.

### Example: Accessing Context and Target

```javascript
public void Execute(IServiceProvider serviceProvider)
{
    IPluginExecutionContext context = (IPluginExecutionContext)
        serviceProvider.GetService(typeof(IPluginExecutionContext));

    IOrganizationServiceFactory serviceFactory =
        (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
    IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

    if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity entity)
    {
        string logicalName = entity.LogicalName;
        Guid id = entity.Id;

        // Example use case: Log the target entity
        tracingService.Trace($"Plugin triggered on entity: {logicalName}, Id: {id}");
    }
}
```

**Use case:** You can use `context` and `Target` to determine whether a specific attribute was updated and conditionally run your logic. For example, only trigger follow-up actions when the **status** of a Case changes.

## Retrieve a Single Record

```javascript
Entity account = service.Retrieve("account",
    new Guid("00000000-0000-0000-0000-000000000001"),
    new ColumnSet("name", "telephone1", "primarycontactid"));

string accountName = account.GetAttributeValue<string>("name");
```

**Use case:** Retrieve account details when a related contact is updated, ensuring consistent synchronization between entities.

## Retrieve Multiple Records (QueryExpression)

```javascript
QueryExpression query = new QueryExpression("contact")
{
    ColumnSet = new ColumnSet("fullname", "emailaddress1", "parentcustomerid")
};
query.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0);
query.Criteria.AddCondition("emailaddress1", ConditionOperator.NotNull);

query.Orders.Add(new OrderExpression("fullname", OrderType.Ascending));

EntityCollection contacts = service.RetrieveMultiple(query);

foreach (var contact in contacts.Entities)
{
    string fullname = contact.GetAttributeValue<string>("fullname");
}
```

**Use case:** Fetch all active contacts with valid email addresses for syncing into a mailing system.

## Retrieve Multiple Records (FetchXML – Advanced)

FetchXML allows more complex queries that are sometimes easier to write than QueryExpression, especially when dealing with joins or aggregates.

### Example 1: Retrieve All Active Opportunities With Related Account Name

```javascript
string fetchXml = @"
<fetch>
  <entity name='opportunity'>
    <attribute name='name' />
    <attribute name='estimatedvalue' />
    <filter>
      <condition attribute='statecode' operator='eq' value='0' />
    </filter>
    <link-entity name='account' from='accountid' to='customerid' alias='acc'>
      <attribute name='name' alias='accountname' />
    </link-entity>
  </entity>
</fetch>";

EntityCollection opportunities = service.RetrieveMultiple(new FetchExpression(fetchXml));
```

**Use case:** Useful when building dashboards or reports that need both opportunity and account details in one query.

### Example 2: Aggregate – Count Active Contacts Per Account

```javascript
string fetchXml = @"
<fetch distinct='false' aggregate='true'>
  <entity name='contact'>
    <attribute name='contactid' aggregate='count' alias='contactcount' />
    <link-entity name='account' from='accountid' to='parentcustomerid' alias='acc'>
      <attribute name='name' groupby='true' alias='accountname' />
    </link-entity>
  </entity>
</fetch>";

EntityCollection results = service.RetrieveMultiple(new FetchExpression(fetchXml));
```

**Use case:** Helps managers quickly see how many contacts each account has, without exporting data.

## Create a Record

```javascript
Entity newContact = new Entity("contact");
newContact["firstname"] = "John";
newContact["lastname"] = "Doe";
newContact["emailaddress1"] = "john.doe@example.com";

Guid contactId = service.Create(newContact);
```

**Use case:** Automatically create a new Contact record when a lead is qualified.

## Update a Record

```javascript
Entity updateContact = new Entity("contact", contactId);
updateContact["telephone1"] = "123-456-7890";

service.Update(updateContact);
```

**Use case:** Update a contact’s phone number whenever the related account’s main phone number changes.

## Delete a Record

```javascript
service.Delete("contact", contactId);
```

**Use case:** Automatically clean up orphaned records when the parent entity is deleted.

## Execute a Special Request

Dynamics 365 CRM includes specialized messages that can be executed through `service.Execute()`.

### Example: Win an Opportunity

```javascript
WinOpportunityRequest winRequest = new WinOpportunityRequest
{
    OpportunityClose = new Entity("opportunityclose")
    {
        ["subject"] = "Opportunity Closed as Won",
        ["opportunityid"] = new EntityReference("opportunity", opportunityId)
    },
    Status = new OptionSetValue(3) // Won
};

service.Execute(winRequest);
```

**Use case:** Automate opportunity closure workflows, such as updating pipeline metrics or notifying stakeholders.

## Conclusion

Plugins in Microsoft Dynamics 365 CRM give developers the ability to enforce business rules directly within the platform’s execution pipeline. By mastering **context**, **target**, and the use of **IOrganizationService**, you can perform everything from simple CRUD operations to complex queries with FetchXML or QueryExpression.

With these skills, you can:

* Validate and enforce business rules before data is saved.
    
* Automatically create or update related records.
    
* Perform advanced queries for reporting or automation.
    
* Execute system messages to integrate seamlessly with CRM processes.
    

Learning to harness these capabilities ensures your plugins are both powerful and efficient, helping organizations get the most from their Dynamics 365 CRM investment.
