Yagasoft Blog http://blog.yagasoft.com Coded Magic! Mon, 29 Jun 2020 19:35:26 +0000 en-US hourly 1 https://wordpress.org/?v=5.4.2 https://i0.wp.com/blog.yagasoft.com/wp-content/uploads/2018/01/star.jpg?fit=32%2C32 Yagasoft Blog http://blog.yagasoft.com 32 32 142110137 CRM Action ‘Object Null Reference’ Error | Oracle Series http://blog.yagasoft.com/2020/06/crm-action-object-null-reference-error-oracle-series?utm_source=rss&utm_medium=rss&utm_campaign=crm-action-object-null-reference-error-oracle-series http://blog.yagasoft.com/2020/06/crm-action-object-null-reference-error-oracle-series#comments Mon, 29 Jun 2020 19:35:26 +0000 http://blog.yagasoft.com/?p=516 Issue In CRM v8.x, calling an Action might fail with the error: ‘Object reference not set to an instance of an object’. The error provided no clues as to the source of the issue;...

The post CRM Action ‘Object Null Reference’ Error | Oracle Series appeared first on Yagasoft Blog.

]]>
Issue

In CRM v8.x, calling an Action might fail with the error: ‘Object reference not set to an instance of an object’. The error provided no clues as to the source of the issue; the first thought was that our code was the issue.

Investigation

Debugging and tracing as we might, all clues led to a platform issue. Upon checking the input parameters, we noticed that some of them are optional. The Entity Reference parameters behave a bit differently when trying to reference them from WF Custom Step parameters: they have a separate entry in the dialogue and we have to choose the ID field from under the referenced Entity.

Now the error makes sense: CRM is trying to access a Field in a Null Object.

Solution

Passing an Empty GUID, and handling it in code as if it’s a Null value, resolves the issue.

More

The post CRM Action ‘Object Null Reference’ Error | Oracle Series appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2020/06/crm-action-object-null-reference-error-oracle-series/feed 1 516
Workflow ‘InvalidCastException’ or ‘Workflow contains an invalid custom activity’ Error | Oracle Series http://blog.yagasoft.com/2020/06/workflow-invalidcastexception-or-workflow-contains-an-invalid-custom-activity-error-oracle-series?utm_source=rss&utm_medium=rss&utm_campaign=workflow-invalidcastexception-or-workflow-contains-an-invalid-custom-activity-error-oracle-series http://blog.yagasoft.com/2020/06/workflow-invalidcastexception-or-workflow-contains-an-invalid-custom-activity-error-oracle-series#comments Sun, 28 Jun 2020 20:40:17 +0000 http://blog.yagasoft.com/?p=510 Issue Sometimes on importing a solution in CRM v8.x, it might fail with the error: ‘Workflow contains an invalid custom activity’. In an effort to try to conquer the ambiguity, I tried to create...

The post Workflow ‘InvalidCastException’ or ‘Workflow contains an invalid custom activity’ Error | Oracle Series appeared first on Yagasoft Blog.

]]>
Issue

Sometimes on importing a solution in CRM v8.x, it might fail with the error: ‘Workflow contains an invalid custom activity’. In an effort to try to conquer the ambiguity, I tried to create said Workflow manually on the target environment.

Adding each step went well until I noticed that one of those steps, namely a certain Custom Step, caused the error: ‘InvalidCastException’. The error might look something like this:

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: System.InvalidCastException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #B947377DDetail: 
<OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
  <ActivityId>b1989af8-b3e2-4e77-b8bc-6630796f0063</ActivityId>
  <ErrorCode>-2147220970</ErrorCode>
  <ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
  <Message>System.InvalidCastException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #B947377D</Message>
  <Timestamp>2020-06-25T09:13:07.4937933Z</Timestamp>
  <ExceptionRetriable>false</ExceptionRetriable>
  <ExceptionSource i:nil="true" />
  <InnerFault i:nil="true" />
  <OriginalException i:nil="true" />
  <TraceText i:nil="true" />
</OrganizationServiceFault>

Investigation

Upon further investigation, it turned out that the Custom Step accepts an Option-set argument with a default value set.

The following code highlights the issue:

        [Input("Option-set Field")]
        [AttributeTarget("new_test", "new_optionsetfieldcode")]
        [Default("1")]
        public InArgument<OptionSetValue> OptionSetFieldArg { get; set; }

On line 3, the Default Attribute caused an error because of the String value. It seems that CRM tries to cast it to an Integer but fails.

Solution

Removing said Attribute fixed the issue.

Resources

Community Thread

More

The post Workflow ‘InvalidCastException’ or ‘Workflow contains an invalid custom activity’ Error | Oracle Series appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2020/06/workflow-invalidcastexception-or-workflow-contains-an-invalid-custom-activity-error-oracle-series/feed 1 510
Ever So Mysterious, O Business Process Flow | Bitesize Series http://blog.yagasoft.com/2020/06/ever-so-mysterious-bpf-bitesize-series?utm_source=rss&utm_medium=rss&utm_campaign=ever-so-mysterious-bpf-bitesize-series http://blog.yagasoft.com/2020/06/ever-so-mysterious-bpf-bitesize-series#comments Fri, 19 Jun 2020 12:25:16 +0000 http://blog.yagasoft.com/?p=475 Microsoft introduced Business Process Flows (BPF) back in version 2013. Developers haven’t really faced critical issues when controlling the BPF through the UI, except for the rare bug here and there. However, it has...

The post Ever So Mysterious, O Business Process Flow | Bitesize Series appeared first on Yagasoft Blog.

]]>
Microsoft introduced Business Process Flows (BPF) back in version 2013. Developers haven’t really faced critical issues when controlling the BPF through the UI, except for the rare bug here and there. However, it has been ever so mysterious to actually understand, clearly, how to control it properly through the SDK. Each member of the community would do their own experiments with the BPF feature, to get it to work in every situation possible.

With Dynamics 365 version of CRM, Microsoft changed/tweaked how BPFs work. The change made it a little bit harder from an SDK point of view. They introduced an instance entity for each BPF, with its stages defined as records in a common entity. Moving through the stages is still fairly straightforward; however, skipping stages might cause an issue, and there are a couple of subtle intricacies of how to get it to work flawlessly.

After some experimentation, and a few issues popping up in projects, I was finally able to write that helper method that would work in every situation. In this article, I will go through the different parts of the code. Please note that I will omit error handling and code structure.

Parameters

Assume you will pass the following information as arguments:

  1. Record: the Reference to the main record utilising the BPF
    • E.g. Case Entity
  2. Process Logical Name: Process Instance Entity Logical Name
    • We can set it as a constant in the code
  3. Process ID: the BPF definition ID
    • Can be found in the BPF editor’s URL
    • Or, can be read from the Process ID in the Record (sometimes it’s empty though; so not consistent!)
  4. Stage ID: ID of the target Stage
    • Can be set as a constant in the code
    • Or, Can be retrieved from the Active Path if all that is required is to move forwards/backwards
  5. Stage Record: the Reference to the record of the current Stage (for multi-entity BPF)
  6. Stage Record Lookup Name: the name of the Lookup in the target Stage Entity (multi-entity BPF) pointing to the main record (Record Entity parameter above)

Example

If we have the following information:

  1. An Entity called Request (new_Request)
  2. Whose BPF is called Resolution Flow (new_BpfResolutionFlow), having the ID: “bea92f8e-dcf4-40b4-b2cc-7b4f835dcf09”
  3. A relation to an Entity called Approval (new_Approval), having a Lookup to the Request (new_RequestId)
  4. The following stages:
    1. Research (Stage ID: f7bed494-4610-46d3-a07e-07d78e2b5fe9)
    2. Decision (Stage ID: bca96646-2414-4dba-a970-b522176362ef)
    3. Approval (points to the Approval Entity, Stage ID: f8db3b4c-585e-474b-8629-529a94dac8f8)
    4. Closure (Stage ID: 4a3e6cc8-741b-4c3e-8b36-9b73b9bd2268)

If we created a new record of the Request Entity having the ID: “7e591173-6983-404a-a132-aa7e9a46df00”, and a related Approval record having the ID: “74bc3837-a312-4298-ba8a-29a8e284180c”, the arguments passed to the code below would be:

  1. Record: EntityReference(“new_Request”, “7e591173-6983-404a-a132-aa7e9a46df00”)
  2. Process Logical Name: “new_BpfResolutionFlow”
  3. Process ID: “bea92f8e-dcf4-40b4-b2cc-7b4f835dcf09”
  4. Target Stage ID: “f8db3b4c-585e-474b-8629-529a94dac8f8”
  5. Stage Record: EntityReference(“new_Approval”, “74bc3837-a312-4298-ba8a-29a8e284180c”)
  6. Stage Record Lookup Name: “new_RequestId”

BPF Instance

We will start by retrieving the BPF Instance record, which we will use in identifying the Instance ID.

var bpfInstance =
  ((RetrieveProcessInstancesResponse)service.Execute(
	new RetrieveProcessInstancesRequest
	{
		EntityId = record.Id,
		EntityLogicalName = record.LogicalName
	})).Processes?.Entities?
	.Select(
		e =>
			new BpfRecord
			{
				LogicalName = processLogicalName,
				Id = e.Id,
				ProcessId = processId,
				StageId = e.GetAttributeValue<Guid?>("processstageid")
			})
	.FirstOrDefault(e => e.ProcessId == processId);

In the code above, BpfRecord is a custom class.

Traversed Path

Next, we need the Active Path of the BPF, which we will use in building the Traversed Path.

var activePath =
  ((RetrieveActivePathResponse)service.Execute(
	new RetrieveActivePathRequest
	{
		ProcessInstanceId = bpfInstance.Id
	})).ProcessStages.Entities
	.Select(s => s.Id);

If the difference between the old and new Traversed Paths is more than one stage, you have to move through the Stages one by one until you reach the target Stage. In other words, CRM does not allow skipping stages anymore (v9). Therefore, we will build the old and new Traversed Paths.

var oldTraversedPath =
  activePath.TakeWhile(s => s != bpfInstance.StageId)
	.Union(new[] { bpfInstance.StageId })
	.Select(s => s.ToString()).Aggregate((e1, e2) => $"{e1},{e2}");
var newTraversedPath =
  activePath.TakeWhile(s => s != stageId)
	.Union(new[] { stageId })
	.Select(s => s.ToString()).Aggregate((e1, e2) => $"{e1},{e2}");

Recursion

Compare the paths. If the logic detects a skip, check the direction of movement and recurse over the logic.

var oldPathLength = oldTraversedPath.Split(',').Length;
var newPathLength = newTraversedPath.Split(',').Length;

if (oldPathLength - newPathLength < -1)
{
	// call this whole logic again (recurse) with the next stage as target
}
else if (oldPathLength - newPathLength > 1)
{
	// call this whole logic again (recurse) with the previous stage as target
}

Move the Stage

Finally, we can update the values that will actually move the stage in CRM.

var updatedProcessRecord =
	new Entity(bpfInstance.LogicalName)
	{
		Id = bpfInstance.Id,
		[$"bpf_{record.LogicalName}id"] = record,
		["activestageid"] = new EntityReference("processstage", stageId)
	};

if (stageRecord != null)
{
	updatedProcessRecord[$"bpf_{stageRecord.LogicalName}id"] = stageRecord;

	// before jumping into a stage entity record, it has to be related to the current record first, if not already so
	if (!string.IsNullOrWhitespace(stageRecordLookupName))
	{
		service.Update(
			new Entity(stageRecord.LogicalName, stageRecord.Id) { [stageRecordLookupName] = record });
	}
}

service.Update(updatedProcessRecord);

Library

The above code exists in my ‘common’ library, which you can download here.

Current State

It used to be so much easier, but Microsoft has been adding validations upon validations that are making it evermore harder to control the BPF through the SDK. Thankfully, with experimentation, we can figure it out, eventually.

More

The post Ever So Mysterious, O Business Process Flow | Bitesize Series appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2020/06/ever-so-mysterious-bpf-bitesize-series/feed 1 475
Office365 AuthType Deprecation – An Alternative | Bitesize Series http://blog.yagasoft.com/2020/06/office365-authtype-deprecation-alternative?utm_source=rss&utm_medium=rss&utm_campaign=office365-authtype-deprecation-alternative http://blog.yagasoft.com/2020/06/office365-authtype-deprecation-alternative#respond Thu, 11 Jun 2020 19:48:18 +0000 http://blog.yagasoft.com/?p=422 Microsoft recently announced the Office365 AuthType deprecation used in connection strings. This AuthType was the popular choice when connecting to Dynamics Online deployments through the SDK. It was indeed very convenient and saved some headache...

The post Office365 AuthType Deprecation – An Alternative | Bitesize Series appeared first on Yagasoft Blog.

]]>
Microsoft recently announced the Office365 AuthType deprecation used in connection strings. This AuthType was the popular choice when connecting to Dynamics Online deployments through the SDK. It was indeed very convenient and saved some headache in properly setting up an Online deployment. Official retirement of Office365 AuthType is next year in April (2021). With many existing alternatives for authentication, there shouldn’t be an issue in making the transition to a supported method.

It doesn’t take much effort, and it’s safer, to use one of the approaches recommended by Microsoft. There are three alternatives to connect to an Online organisation: OAuth, Certificate, and Client Secret. I will discuss OAuth and Client Secret methods in this article.


OAuth

OAuth type can be used when building an app with direct user interaction. The user has to have an Office account, as there will be a popup requesting a username and password from the user.

Connection String

It can also be used for API/unattended access. The connection string template is as follows:

AuthType=OAuth; Username={username}; Password={password}; Url=https://{org}.{region}.dynamics.com/; AppId={appId}; RedirectUri=app://{appId}; LoginPrompt=Never

The connection string is pretty simple and straightforward. Let me show you how to acquire the AppId, and how to properly configure your tenant for access.

AppId

Login on to Azure portal, and search for Azure Active Directory.

Click on App Registrations.

Select New Registration.

Enter a name for your app, and then click Register.

The Application ID is highlighted below. Use it to replace the appId placeholder in the connection strings.

API Permissions

Select API Permissions from the side menu, and then add a new Permission.

Click on Dynamics 365.

Choose user_impersonation Permission, and then click Add.

Click Grant Admin Consent.

Public Access

Allow App Permission to be public: select Authentication, choose Yes under Default Client Type, and then click Save at the top of the page.


ClientSecret

For our purpose, ClientSecret is the appropriate replacement for the Office365 AuthType. The connection string template is as follows:

AuthType=ClientSecret; url=https://{org}.{region}.dynamics.com; ClientId={appId}; ClientSecret={clientSecret}

The connection string is simple as well. Let me show you how to acquire the ClientSecret, and how to properly configure your organisation to control privileges for this connection.

In this string, ClientId is equivalent to AppId in the previous type (OAuth).

Azure Configuration

Proceed to create the same App Registration as in the OAuth section above, following the steps in the AppId and API Permissions sections only.

ClientSecret

Select Certificates & Secrets, and then click on New Client Secret.

Choose your preferred expiry period.

Copy the Client Secret string, and replace the clientSecret placeholder in the connection strings.

Organisation Configuration

Open the target CRM organisation, and navigate to the Security -> Users section. Select the Application Users view, and create a new User.

Paste the Application ID with the value retrieved from Azure in the above sections; the rest of the data is redundant.

Assign a security role to the new User, just like any other user in CRM.

I personally prefer the Client Secret method; as I find it more practical, easy to set up as a service account, and secure.

It was just a matter of time before Microsoft forced Office365 AuthType deprecation, considering that the alternative methods are used in many web applications; I have to say that this was an inevitable shift.

The post Office365 AuthType Deprecation – An Alternative | Bitesize Series appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2020/06/office365-authtype-deprecation-alternative/feed 0 422
CRM Developer Guidelines http://blog.yagasoft.com/2019/12/crm-developer-guidelines?utm_source=rss&utm_medium=rss&utm_campaign=crm-developer-guidelines http://blog.yagasoft.com/2019/12/crm-developer-guidelines#comments Thu, 12 Dec 2019 19:52:25 +0000 http://blog.yagasoft.com/?p=388 In most engineering disciplines, there exists a set of guidelines in every field that ensures a high-quality delivery and the highest resistance to unexpected failure after going live. This is evident in our attempt...

The post CRM Developer Guidelines appeared first on Yagasoft Blog.

]]>
In most engineering disciplines, there exists a set of guidelines in every field that ensures a high-quality delivery and the highest resistance to unexpected failure after going live. This is evident in our attempt to set as much of a foolproof software development process as possible; e.g. DevOps. In this article, I will explore some of the most effective CRM developer guidelines based on extensive research and the best expertise in our field.

Why bother?

Imagine building a tower without any rules to ensure safety, programming an aeroplane without constraints on performance, or creating sensitive medical equipment without limits on its accuracy and precision; guidelines make for higher quality products as efficient as possible.

Same applies to software: we could build a solution, perform testing, and then find out that under a certain type of load it fails; repeat the cycle again, wasting valuable effort. Alternatively, avoid what could lead to said failures, from the start, by following a set of principles. Those principles are usually shared by experienced people who fell into those pitfalls before us.

Sample of Important Developer Guidelines

Avoid using Object Type Codes

Object Type Codes change between environments. Sure, the out-of-the-box entities stay the same, but that’s because the core DB is practically cloned on organisation creation; however, when you create a new entity and then import it into a new environment, its Code is not maintained.

Never access the DB directly

Back in CRM 2011, there used to be two tables per entity. After CRM 2013 was released, the tables were officially merged to what we see today. Just knowing this fact would drive you to be cautious about directly accessing the DB for query or manipulation. It is definitely a major headache to maintain unsupported code when Microsoft decides to modify the internal workings of CRM.

Use Source Control

Even if you are working alone, or the company policy does not enforce a Source Control, it is highly recommended to use one. It allows for experimenting, parallel development, and bookkeeping with ease.

Don’t access the DOM

The same reasoning as ‘Never access the DB directly’: avoid accessing any code/component not supported for such access by Microsoft.

Use ‘getClientUrl’ instead of hardcoding the URL in code

It is recommended to avoid hardcoding any values that might change between environments during deployment. Even more so, it is recommended not to hardcode any values into your code. The better approach is to move configurations into a separate module and fetch those values using a standardised method.

Use OData v4 (Web API) instead of OData v2 or SOAP endpoint

OData v2 and SOAP are deprecated and will be removed soon; so, it’s best to avoid those APIs to have peace of mind when upgrading/updating CRM in the future.

Don’t use class-level variables in plugins

I cannot count how many times this has caused issues in production. Under certain loads, in certain entities, variables on the level of the IPlugin class could cause unpredictable and strange errors. It’s impossibly hard to debug and trace. Moreover, it easily leads to data integrity issues.

Avoid the following:

public class MyPlugin : IPlugin
{
	private IOrganizationService service;	// bad!

	public void Execute(IServiceProvider serviceProvider)
	{
		var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
		var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
		service = serviceFactory.CreateOrganizationService(null);
	}
}

Don’t use threading in plugins

Plugins are not thread-safe. Using ‘locks’, ‘threads’, or the like in plugins causes unexpected behaviour — similar to class-level variables.

Separate web applications from CRM’s

In old versions of CRM, there used to be a folder where ISVs could host their applications under CRM. This is not the case anymore. In addition, hosting non-CRM apps under CRM’s in IIS could cause conflicting issues that you are better off avoiding. Finally, it provides for better security.

Define the ownership at entity creation

I have seen this too many times: some developers hastily set the Ownership of the entity to Organisation instead of User/Team. Unfortunately, this cannot be modified easily, which causes a major headache later when the need arises to use user-level security. Reserve Organisation setting to only entities that will never be owned by users; e.g. Countries.

Disable all options on entity creation

Some options cannot be disabled once enabled when creating an entity. For example, if you enable Business Process Flows, it will create fields and entities that cannot be deleted later, which could clatter the system unnecessarily. Said options usually have this sign ‘†’ appended.

Assign least privileged role and minimise security privileges

From a best-practice business perspective, users should never be allowed to do more than what they are allowed to by their company role. CRM aims to automate the company’s business; so, it should be a reflection of its rules as well. Restrict users to do what they are supposed to only.

Consider that fields are accessible in Advanced Find

A solution could be locked down tight from a UI perspective on the form — locked fields and such; however, the user can work around this by searching for the record and viewing/editing it through Advanced Find. To counter this exploit, one option might be to set the field as ‘unsearchable’. If the field must be searchable, add validation in a plugin to ensure that the business rules are adhered to at all times from any access point. For even higher security, enable Field Level Security on said field.

Full Guidelines Download Links

CRM Developer Guidelines – v1.4 – Word Document

CRM Developer Guidelines – v1.3 – Excel Sheet

Inlined Table

For convenience, below is the Excel sheet linked above.

Guideline Description Category Sub-category Severity Comments

References

Reference Link
Microsoft Dynamics CRM Implementation Guide for CRM Online and CRM 2016 (on-premises) https://www.microsoft.com/en-us/download/details.aspx?id=50039 
Microsoft Dynamics CRM Implementation Guide for CRM 2015 https://www.microsoft.com/en-ca/download/details.aspx?id=45022
Microsoft Dynamics CRM Software Development Kit (SDK) for CRM Online and on-premises CRM 2016 https://www.microsoft.com/en-us/download/details.aspx?id=50032
Microsoft Dynamics CRM 2015 Software Development Kit (SDK) https://www.microsoft.com/en-us/download/details.aspx?id=44567
Microsoft Dynamics CRM 2015 and Microsoft Dynamics CRM 2016 Performance and Scalability Documentation https://www.microsoft.com/en-us/download/details.aspx?id=45905
Optimizing and maintaining the performance of a Microsoft Dynamics CRM 2011 server infrastructure https://www.microsoft.com/en-us/download/details.aspx?id=27139
Optimizing and maintaining client performance for Microsoft Dynamics CRM 2011 and CRM Online https://www.microsoft.com/en-us/download/details.aspx?id=23261
Deploying Microsoft Dynamics CRM 2011 and CRM Online Solutions from Development through Test and Production Environments https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=27824
Patterns and Principles for CRM Online Solution Builders https://blogs.msdn.microsoft.com/crm/2015/04/29/microsoft-dynamics-crm-online-patterns-principles-for-solution-builders/
Microsoft Dynamics Sure Step https://mbs.microsoft.com/customersource/Global/SureStep
Dynamics CRM Community http://www.microsoft.com/dynamics/crm/community/default.mspx
Dynamics CRM on MSDN http://msdn2.microsoft.com/en-us/dynamics/crm/default.aspx
Premier Field Engineering CRM in the Field blog http://blogs.msdn.com/b/crminthefield/
Dynamics CRM Product Team Blog http://blogs.msdn.com/b/crm/
Microsoft Dynamics CRM Online patterns & principles for solution builders white paper http://go.microsoft.com/fwlink/p/?LinkID=533946 
Best practices for developing with Microsoft Dynamics CRM https://msdn.microsoft.com/en-us/library/gg509027.aspx
Dynamics CRM and User Experience (UX) https://crmgiant.eu/research-and-discussion/dynamics-crm-and-user-experience-ux/

The post CRM Developer Guidelines appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2019/12/crm-developer-guidelines/feed 1 388
Testing Dynamics CRM – Plugins | Capsule Series http://blog.yagasoft.com/2019/03/testing-dynamics-crm-plugins?utm_source=rss&utm_medium=rss&utm_campaign=testing-dynamics-crm-plugins http://blog.yagasoft.com/2019/03/testing-dynamics-crm-plugins#comments Wed, 20 Mar 2019 15:30:16 +0000 http://blog.yagasoft.com/?p=368 You are reading the third part of the main article: Testing Dynamics CRM. A plugin is custom code that runs within CRM’s process. However, when unit testing, we have to isolate the environment in...

The post Testing Dynamics CRM – Plugins | Capsule Series appeared first on Yagasoft Blog.

]]>
You are reading the third part of the main article: Testing Dynamics CRM.


A plugin is custom code that runs within CRM’s process. However, when unit testing, we have to isolate the environment in which the plugin code runs. In addition, we need to provide the parameters required to successfully execute.

The first order of business is to analyse the parameters provided to the plugin by its interface definition. CRM provides only one parameter, namely IServiceProvider. This service provider object facilitates the extraction of services. Of which, there are three important ones we all use: IOrganizationServiceFactory, IPluginExecutionContext, and ITracingService.

The Tool

We will mock/fake/simulate the three services as best we can. Well … a really good developer did all the heavy-lifting for us: Jordi Montana.

He created a framework called FakeXrmEasy. Here’s a snippet from his website describing the framework:

FakeXrmEasy is an open source framework built on top of Fake It Easy which adds a layer specifically designed for Dynamics CRM to mock IOrganizationService calls for you. It also keeps track of every entity from plugins, code activities, queries, and any other 3rd party app accessing the IOrganizationService in a context which runs In Memory, blazingly fast.

FakeXrmEasy helps you effectively maintain a healthy CRM ecosystem by reducing the time needed to write tests for: Plugins, Code Activities, and Other code.

https://dynamicsvalue.com/home

FakeXrmEasy is available on NuGet for easy installation into a test project.

IOrganizationService

First step is to create the framework’s main object. The object will handle everything for us, from execution to querying.

var xrmFakedContext = new XrmFakedContext();

There are two types of organisation services. One is connected to a DB in memory, and has nothing to do with CRM’s deployment at all. The other actually connects to CRM directly and runs queries against its API.

Unit tests are pointless if you pollute them with external factors outside their control. Therefore, connecting to CRM directly defeats the point of creating those tests in the first place. I would definitely avoid a direct connection, except maybe to run integration tests.

var service = xrmFakedContext.GetOrganizationService();

IPluginExecutionContext

Now comes the interesting part: building the plugin context. We will add everything the plugin code might ever need from the context. That includes InputParameters, MessageName, UserId, EntityImages … etc.

For example, let’s assume our post-operation plugin is registered on the update of an account number. In addition, it requires a post image containing the account name and fax. The preparation code might look like this:

var target =
    new Account
    {
        Id: Guid.NewGuid(),
        AccountNumber: "12345"
    };

var image =
    new Account
    {
        Name: "Contoso",
        Fax: "111-111-1111"
    };

var fakedContext =
    new XrmFakedPluginExecutionContext
    {
        MessageName = "Update",
        Stage = 40,
        InputParameters = new ParameterCollection { ["Target"] = target },
        PostEntityImages = new EntityImageCollection { ["image"] = image }
    };

Supporting Data

Assume that the plugin will retrieve the list of related contacts. Therefore, we will proceed with creating one.

var contact =
    new Contact
    {
        FirstName: "John",
        LastName: "Doe",
        Email: "john@test.com",
        CompanyName: new EntityReference(target.LogicalName, target.Id)
    };

contact.Id = service.Create(contact);

Notice how we used the faked service to create a record. FakeXrmEasy created the record in a DB in memory for us to query anytime.

Execute

Let’s run the test.

xrmFakedContext.ExecutePluginWith<PostUpdateAccountNotifyContact>(fakedContext);

Notice how we passed the plugin type (PostUpdateAccountNotifyContact) as a type parameter to the execution function.

Assert

After the test has finished, we need to make sure that its effect on the system is what we desire. In our case, the plugin is supposed to create an email. Hence, we should check that one was created.

var query =
    new QueryExpression(Email.EntityLogicalName)
    {
        TopCount = 1,
        ColumnSet = new ColumnSet(false)
    };

var result = service.RetrieveMultiple(query).Entities;
Assert.IsNotEmpty(result);

Conclusion

What I covered above was the most straightforward scenario to test a plugin. Plugins are not supposed to be complex; therefore, most will be simple enough for the above to satisfy their testing requirements.

For more advanced functionalities, and for testing custom steps, please refer to Jordi’s website.


In the next part of the article, I will try to simplify the already-complex chore that is testing JS code.

The post Testing Dynamics CRM – Plugins | Capsule Series appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2019/03/testing-dynamics-crm-plugins/feed 2 368
Import a Dynamics Organisation v8 to a v9 Installation http://blog.yagasoft.com/2019/03/import-v8-organisation-v9-install?utm_source=rss&utm_medium=rss&utm_campaign=import-v8-organisation-v9-install http://blog.yagasoft.com/2019/03/import-v8-organisation-v9-install#comments Sun, 10 Mar 2019 09:39:31 +0000 http://blog.yagasoft.com/?p=346 Importing an organisation from Dynamics CRM v8 to v9 can be a bit troublesome. You might face strange errors like the ones below. Fortunately, in this article, I compiled a list of possible issues...

The post Import a Dynamics Organisation v8 to a v9 Installation appeared first on Yagasoft Blog.

]]>
Importing an organisation from Dynamics CRM v8 to v9 can be a bit troublesome. You might face strange errors like the ones below. Fortunately, in this article, I compiled a list of possible issues and their solutions.

SQL Assembly Error

First issue you might face is a SQL assembly error. It looks something similar to this:

Error| Upgrade Organization with Id=xyz failed with Exception: System.Exception: Error.ActionFailed Microsoft.Crm.Tools.Admin.UpgradeDatabaseAction ---> Microsoft.Crm.CrmException: Error in Action: Bin\Microsoft.Crm.DataUpgrade.dll:TrackCustomDatabaseObjects on attempt 3. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.SqlServer.Smo, Version=xx.0.0.0, Culture=neutral, PublicKeyToken=uvw' or one of its dependencies. The system cannot find the file specified.    at Microsoft.Crm.DataUpgrade.DatabaseObjectChangeTracker.GenerateScriptForIndex(String tableName, String indexName, ISqlExecutionContext sqlContext)    at Microsoft.Crm.DataUpgrade.DatabaseObjectChangeTracker.InsertObjectTrackerTableInput(List`1 inputData, String tableName, ISqlExecutionContext sqlContext)    at Microsoft.Crm.DataUpgrade.DatabaseChangeTracker.TrackCustomDatabaseObjects()    --- End of inner exception stack trace ---  An error occurred when trying import and upgrade organization database CRMSERVER.CRMDEV_MSCRM: Microsoft.Crm.CrmException: Upgrade Organization with Id=xyz failed with Exception: System.Exception: Error.ActionFailed Microsoft.Crm.Tools.Admin.UpgradeDatabaseAction ---> Microsoft.Crm.CrmException: Error in Action: Bin\Microsoft.Crm.DataUpgrade.dll:TrackCustomDatabaseObjects on attempt 3. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.SqlServer.Smo, Version=xx.0.0.0, Culture=neutral, PublicKeyToken=uvw' or one of its dependencies. The system cannot find the file specified.

The solution is to install the following four packages:

  • System CLR Types x86: link
  • System CLR Types x64: link
  • Shared Management Objects x86: link
  • Shared Management Objects x64: link

Marketing Solution Error

After fixing the issue above, you might get something similar to the following:

Info| Failed to install msdynce_MarketingSalesException: Microsoft.Crm.PackageDeployment.PackageDeployerException: Package msdynce_MarketingSales failed to install on attempt 1. System.AggregateException: One or more errors occurred. ---> Microsoft.Crm.MultiTenantPackageDeployment.PackageDeployerImportException: PackageDeployerWrapper: Import Failed status encountered. Details: Failed to load solution Marketing Sales Patch, version: xx. See the log file.    at Microsoft.Crm.MultiTenantPackageDeployment.PdExecutor.Process(PackageDeploymentInputArgs input, JobOutput`1 output, CancellationToken ct)    at System.Threading.Tasks.Task.Execute()    --- End of inner exception stack trace --- ---> (Inner Exception #0) Microsoft.Crm.MultiTenantPackageDeployment.PackageDeployerImportException: PackageDeployerWrapper: Import Failed status encountered. Details: Failed to load solution Marketing Sales Patch, version: xx. See the log file.    at Microsoft.Crm.MultiTenantPackageDeployment.PdExecutor.Process(PackageDeploymentInputArgs input, JobOutput`1 output, CancellationToken ct)    at System.Threading.Tasks.Task.Execute()<--- 

The workaround is to edit the ImportConfig.xml file at:

C:\Program Files\Dynamics 365\Setup\Serviceability\Latest\Actions_Org\Install\Packages\CRMApps\PkgCache_9_0_000y_xx\msdynce_MarketingSales\msdynce_MarketingSales

Open the file and comment the following line:

<configsolutionfile solutionpackagefilename="msdynce_MarketingSalesPatch_managed.cab" publishworkflowsandactivateplugins="true" />

Full-text Indexing Errors

You might faced this error only when importing the same DB after the above failed attempts. Importing on a clean restored DB did not produce that error for me.

Cannot drop index 'cndx_PrimaryKey_ColumnMapping' because it enforces the full-text key for table or indexed view 'ColumnMappingBase'.

To resolve the issue, delete the full text indexing from the following tables:

  • ColumnMappingBase
  • PrivilegeBase
  • ImportEntityMappingBase
  • ImportMapBase
  • WebWizardBase
  • TransformationParameterMappingBase

To remove a full-text index: in Object Explorer, right-click the table, select Delete Full-Text Index.

Important Note

The above issues are not the only ones you might face, of course. Hence, to avoid hair-pulling moments, after every failed attempt, you must import again on a clean restored DB; otherwise, you will face strange errors that are hard to resolve.

In addition, workarounds can cause unpredictable issues; you must retest your whole solution to make sure it works as expected.

References

The post Import a Dynamics Organisation v8 to a v9 Installation appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2019/03/import-v8-organisation-v9-install/feed 5 346
Virtual Entities: ID and Relation Workarounds http://blog.yagasoft.com/2019/03/virtual-entities-work-arounds?utm_source=rss&utm_medium=rss&utm_campaign=virtual-entities-work-arounds http://blog.yagasoft.com/2019/03/virtual-entities-work-arounds#comments Fri, 01 Mar 2019 08:25:46 +0000 http://blog.yagasoft.com/?p=324 UPDATE (2019-12-27): I tested adding CRM entity lookups to Virtual Entities in the latest version and it seems to work just fine. I will test it further and report any issues that might pop...

The post Virtual Entities: ID and Relation Workarounds appeared first on Yagasoft Blog.

]]>
UPDATE (2019-12-27): I tested adding CRM entity lookups to Virtual Entities in the latest version and it seems to work just fine. I will test it further and report any issues that might pop up.


Virtual Entities was a much needed feature in Dynamics CRM until its introduction in v9. It facilitates querying data in real-time that exists in an external system.

It used to be that we had to synchronise and save a copy of the data locally in order to access it seamlessly. That approach created a headache: outdated, missing, or erroneous data; in addition to the wasted space to save the data locally.

With the introduction to Virtual Entities (VEs), you get to link external data sources with local schema. It is done in such a way that by accessing the data just like a normal entity, the system automatically queries the other system instead of the local DB seamlessly.

The Catch

With such flexibility comes a few limitations. It is understandable considering that it’s still in its infancy.

I will list the two missing features that could greatly expand the scope of usage in most projects. That is my prespective only, and it does not reflect the community’s point of view, of course.

Non-GUID Primary Keys

Dynamics CRM has a unified system of IDs; it uses GUIDs as the primary key format for all tables in its DB.

When dealing with other systems, we will definitely find other key formats; however, CRM assumes that those keys are in the same format. It creates an easy implementation for the feature, but severely limits its adoption.

1-N relations

One to many relations between CRM entities and VEs are not supported. You can indeed add a lookup to VEs but as soon as you query the entity, the system throws an error.

Lookups in VEs exist to relate external entities to each other, mirroring the external schema. However, creating a link with CRM entities does not work, and it makes sense that it should not. Unless the two systems are tightly coupled, or at least developed to be linked, the other system is not aware of CRM and its ID system. On the other hand, when using VEs you are explicitly creating a dependency between CRM and another system.

The good news is that N-1 relations are supported; CRM entities can lookup VEs, just like normal entities.

Solutions

One way to overcome this limitation is to adapt the external system to CRM’s. This is by no means a practical solution.

Another approach would be to create a custom data provider in CRM to handle the different format or schema. However, custom providers are a major hassle to implement. They require handling too many variables that you would question its worth. Check this article if you would like to explore this option.

The most effective solution would be to wrap the external service with your own, creating a proxy that create mappings to handle all issues you might face.

I will go in depth in the next section, explaining the technical details of how to implement this solution.

Implementation

Proxy Service Setup

Let’s assume we have an external system that contains the transaction history of accounts.

Create an empty Web API project.

Install OData v4 web service by installing NuGet package Microsoft.AspNet.OData.

Create a model for the transactions:

public class Transaction
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public decimal Amount { get; set; }
    public string Account { get; set; }
}

Add the following lines to the function Register in the WebApiConfig file:

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Transaction&gt;("Transactions");
config.MapODataServiceRoute("odata", null, builder.GetEdmModel(),
    new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
config.EnsureInitialized();

Create the following controller:

[EnableQuery]
public class TransactionsController : ODataController
{
    private static readonly IQueryable<Transaction&gt; transactions =
        new List<Transaction&gt;
        {
            new Transaction { Id = Guid.NewGuid(), Title = "Pay Subscription", Amount = 100},
            new Transaction { Id = Guid.NewGuid(), Title = "Buy Gold Package", Amount = 5000,
                                Account = "565C78F5-142D-E911-A62D-00155D313700" }
        }.AsQueryable();

    public IQueryable<Transaction&gt; Get()
    {
        return transactions;
    }

    public Transaction Get([FromODataUri] Guid key)
    {
        return transactions.FirstOrDefault(p =&gt; p.Id == key);
    }
}

CRM Setup

We already have all accounts in CRM, but we don’t need the transaction history to be saved locally because they are read-only.

We’ll create a VE for the transactions. Add an account field of type text (remember we can’t have local lookups in VEs). This field will hold the account’s ID in CRM as a string.

Add a sub-grid on the account form listing all transactions.

Virtual Entity sub-grid configuration to return all records

Relation Solution

The current sub-grid will retrieve all transactions in the external system, which does not serve our purpose.

Virtual Entity sub-grid showing all record returned

To filter the retrieved records, we need to inject a condition on the account’s field in the transaction records. To achieve this, we will modify the FetchXML query of the sub-grid in an unsupported manner; hopefully, Microsoft will add a supported method soon.

Use the following code on the Account form:

function filterTransactions(executionContext)
{
    var formContext = executionContext.getFormContext();

    var htmlGrid = window.parent.document.getElementById("Transactions");
    var controlGrid = formContext.getControl("Transactions");

    var id = formContext.data.entity.getId();

    controlGrid.addOnLoad(function () // make sure that the grid is loaded
    {
        var fetchXml =
            '<fetch version="1.0" output-format="xml - platform" mapping="logical" distinct="true"&gt; '
                + '<entity name = "ldv_transaction" &gt; '
                + '<attribute name="ldv_name" /&gt; '
                + '<attribute name="ldv_amount" /&gt; '
                + '   <filter type="and"&gt; '
                + '       <condition attribute="ldv_account" operator="eq" value="' + id.replace(/[{}]/gi, '').toUpperCase()
                + '" /&gt;'
                + '   </filter&gt; '
                + ' </entity &gt; '
                + ' </fetch &gt; ';

        htmlGrid.control.SetParameter("fetchXml", fetchXml);

        // refresh grid to show filtered records only.
        htmlGrid.control.Refresh();
    });
}

Call filterTransactions on form load.

Notice the following line:

<condition attribute="ldv_account" operator="eq" value="' + id.replace(/[{}]/gi, '').toUpperCase()

Which filters the returning records to only ones related to this account.

Virtual Entity sub-grid showing only a single record returned

Non-GUID Keys

If the external system uses non-GUID primary keys, we will have to find a way to link the same record in both systems using their respective ID format. I will present here two ways of doing it.

First, we could create an intermediate database. When we receive a request from CRM on the web service above, map the IDs returned from the data source to new GUIDs. The IDs are store as mappings in the intermediate DB for when the same record is being returned.

This solution is not necessary if the external system’s IDs are short enough.

A clever workaround would be to encode the IDs into a base GUID using a standardised algorithm, and return the result to CRM. Let me show you how we can do so.

Let’s change the model to reflect the external system’s ID system:

public abstract class TransactionBase
{
    public string Title { get; set; }

    public decimal Amount { get; set; }

    public string Account { get; set; }
}

public class Transaction : TransactionBase
{
    public int Id { get; set; }
}

public class TransactionCrm : TransactionBase
{
    public Guid Id { get; set; }
}

We also need to provide CRM with the new model in the WebApiConfig:

builder.EntitySet<TransactionCrm&gt;("Transactions");

Next step would be to encode the returned IDs into a base GUID for CRM:

[EnableQuery]
public class TransactionsController : ODataController
{
    private static readonly IQueryable<Transaction&gt; transactions =
        new List<Transaction&gt;
        {
            new Transaction { Id = 1, Title = "Pay Subscription", Amount = 100},
            new Transaction { Id = 2, Title = "Buy Gold Package", Amount = 5000,
                                Account = "565C78F5-142D-E911-A62D-00155D313700" }
        }.AsQueryable();
    private static readonly Guid baseGuid = Guid.NewGuid();

    public IQueryable<TransactionCrm&gt; Get()
    {
        return MapModel(transactions);
    }

    public TransactionCrm Get([FromODataUri] Guid key)
    {
        return MapModel(transactions).FirstOrDefault(t =&gt; t.Id == key);
    }

    private static IQueryable<TransactionCrm&gt; MapModel(IQueryable<Transaction&gt; transactions)
    {
        var baseGuidString = baseGuid.ToString("N").ToUpper();
        return transactions
            .Select(t =&gt; // use auto-mapper
                new TransactionCrm
                {
                    Id = Guid.Parse(baseGuidString.Remove(baseGuidString.Length - t.Id.ToString().Length) + t.Id),
                    Title = t.Title,
                    Amount = t.Amount,
                    Account = t.Account
                });
    }
}

Of course, you have to handle the following cases for IDs:

  • Contain letters: make sure they are Hex-encoded
  • Length is greater than 32 after encoding: use the first method (DB mapping)

Final Thoughts

VEs is a great feature that has the potential to reduce projects’ implemention effort, drastically in some cases. In this article, I have introduced a solution to two frustrating issues that would prevent the adoption of VEs in some projects.

Hopefully, Microsoft will address those issues soon enough, or provide us with a supported alternative for some parts of the code used above.

Credits

Relation solution designed in co-ordination with @amrattia (LinkedIn).

The post Virtual Entities: ID and Relation Workarounds appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2019/03/virtual-entities-work-arounds/feed 1 324
Testing Dynamics CRM – Plugins and JS [Video] http://blog.yagasoft.com/2018/12/testing-dynamics-crm-plugins-and-js-video?utm_source=rss&utm_medium=rss&utm_campaign=testing-dynamics-crm-plugins-and-js-video http://blog.yagasoft.com/2018/12/testing-dynamics-crm-plugins-and-js-video#respond Thu, 27 Dec 2018 15:08:18 +0000 http://blog.yagasoft.com/?p=311 This session covers the basics of testing custom workflow steps and XRM JS code using their respective test frameworks. The audio is in Arabic.

The post Testing Dynamics CRM – Plugins and JS [Video] appeared first on Yagasoft Blog.

]]>
This session covers the basics of testing custom workflow steps and XRM JS code using their respective test frameworks. The audio is in Arabic.

The post Testing Dynamics CRM – Plugins and JS [Video] appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/12/testing-dynamics-crm-plugins-and-js-video/feed 0 311
Testing Dynamics CRM – Introduction [Video] http://blog.yagasoft.com/2018/12/testing-dynamics-crm-introduction-video?utm_source=rss&utm_medium=rss&utm_campaign=testing-dynamics-crm-introduction-video http://blog.yagasoft.com/2018/12/testing-dynamics-crm-introduction-video#respond Thu, 27 Dec 2018 15:07:27 +0000 http://blog.yagasoft.com/?p=312 This session covers testing concepts and how they relate to Dynamics CRM. The audio is in Arabic.

The post Testing Dynamics CRM – Introduction [Video] appeared first on Yagasoft Blog.

]]>
This session covers testing concepts and how they relate to Dynamics CRM. The audio is in Arabic.

The post Testing Dynamics CRM – Introduction [Video] appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/12/testing-dynamics-crm-introduction-video/feed 0 312
Testing Dynamics CRM – Breakdown | Capsule Series http://blog.yagasoft.com/2018/12/testing-dynamics-crm-breakdown?utm_source=rss&utm_medium=rss&utm_campaign=testing-dynamics-crm-breakdown http://blog.yagasoft.com/2018/12/testing-dynamics-crm-breakdown#respond Sun, 23 Dec 2018 09:46:07 +0000 http://blog.yagasoft.com/?p=275 You are reading the second part of the main article: Testing Dynamics CRM. Dynamics CRM can be divided into logical units that facilitate its testing by slightly adding twists to known methods wrapped in...

The post Testing Dynamics CRM – Breakdown | Capsule Series appeared first on Yagasoft Blog.

]]>
You are reading the second part of the main article: Testing Dynamics CRM.


Dynamics CRM can be divided into logical units that facilitate its testing by slightly adding twists to known methods wrapped in innovative tools. Let’s define the problem of each testable piece first to find value in what those tools provide us.

Database

In order to test any of the following units, we must simulate our data in memory somehow. For example, if we assume that our business logic associates a contact with a parent account, automatically using a plugin, then we have two ways to go about it.

One way is to directly map each request to a predefined response. This approach is, of course, tedious and wastes too much time. In addition, if the query changes for any reason, the developer must change the mapped response as well. This makes the whole system fragile.

The other approach is to provide the mocking engine with a list of accounts to choose from and the engine handles processing the request. This effectively simulates the query engine in memory. It requires so much more effort to get it right and cover all the details, but the reward makes it so worth the headache.

SDK

Testing the SDK in any context requires simulating all web service calls to CRM on our machine. Successfully simulating this amount of calls is a feat on its own right: from simple CRUD operations; to complex data and metadata queries, and an enormous number of specialised messages.

The time spent to build such a framework must be justified; is it worth the effort or should we favour the short term and fake each call, in code, on the fly.

Plugins

Plugins and custom steps have the same fundamental issue: they both run inside CRM in a special environment. This makes testing them a little bit harder than usual.

Both require the developer to build a special object — the context — containing parameters that are provided at runtime. For example, the message, target of execution, user and organisation ID, queried data … etc. Preparing those parameters can be tedious, which could become a burden on developers, leading them to skip testing altogether.

JS

Client-side code requires a library which is provided at runtime on page load in CRM. The client-side SDK is composed of well-defined functionality groups, each group performs a simple action on the form. Considering there aren’t that many actions compared to the server-side SDK, mocking can definitely be done relatively easy.

There is still the issue of testing web service calls, but it’s not specific to JS, or CRM for that matter.

System Flow

What if you want to test the effect of creating a record? Which plugins and WFs would fire, in what order, and let’s debug them on the fly while we are at it. Simulating this whole flow on your machine is definitely a dream for us, or any software engineer for that matter.

We have to build the plugin contexts on the fly, order their execution correctly, and track their effect on CRM. For WFs, we have to build an execution engine and parse their XAML correctly.

UI

QC teams usually performs system testing through the UI. Manual testing might not be the best approach in this case, due to our tendency to overlook details when faced with repeated actions.

There are two approaches to automating UI testing. Either use software that support recording a scenario, following user interactions with the UI, or manually write code that performs a series of actions on the UI when run.

Both would work in CRM to a degree; the issue is that CRM has a complex system of I-Frames and HTML structure. It takes some effort to trace the elements and their IDs needed for simulating actions. Even when you record the actions, you still need to tweak the steps due to animations and delays, changing frame IDs, or unique input elements, for example.


In the next part of the article, we will go deeper into the details of the testing activity itself from different perspectives using specific tools.

The post Testing Dynamics CRM – Breakdown | Capsule Series appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/12/testing-dynamics-crm-breakdown/feed 0 275
Testing Dynamics CRM – The Discipline | Capsule Series http://blog.yagasoft.com/2018/12/testing-dynamics-crm-discipline?utm_source=rss&utm_medium=rss&utm_campaign=testing-dynamics-crm-discipline http://blog.yagasoft.com/2018/12/testing-dynamics-crm-discipline#respond Tue, 04 Dec 2018 09:12:19 +0000 http://blog.yagasoft.com/?p=260 Software is developed by humans, whose propensity for making mistakes is undeniable. Catching those mistakes is paramount to delivering quality solutions to eager customers. Testing is the activity of squashing those bugs. It is...

The post Testing Dynamics CRM – The Discipline | Capsule Series appeared first on Yagasoft Blog.

]]>
Software is developed by humans, whose propensity for making mistakes is undeniable. Catching those mistakes is paramount to delivering quality solutions to eager customers. Testing is the activity of squashing those bugs. It is an integral part of the software development life-cycle, without which users/customers would be our human Guinea pigs; customer’s trust and satisfaction would take a tumble, and projects would probably fail miserably.

The first part of this article will go over testing in general. I won’t go into too much detail, as this is not the goal of the article. Specifics of Dynamics CRM testing will be covered in later parts of the article.

Is it worth it?

We tend to build in pieces. Imagine building a car, creating the body, wheels, engine, brakes … etc. Only to discover, after going to production, that customers are complaining about measly acceleration. At that stage, you have to recall, make adjustments, and deploy again — a huge waste of time and money. Only to fail again due to another unforeseen issue. Testing every aspect of the product before even building a single car could have avoided such a massive hit; test the engine alone under the expected load.

One National Institute of Standard Technology study found that without testing, a 5 hour-fix of a defect in development can take up to 3 times as much if discovered in production.

Prove it!

Some might get away with ship-stopper issues on their blog pages, informational web sites, or even open source small non-financial projects. The most damage incurred would be a loss of a few readers, visitors, or users. Enterprise applications, however,  don’t have it so easy. For example, some of Amazon’s third party retailers saw their product price reduced to 1p due to a software glitch, back in 2014 (link). They were left with heavy losses, and some businesses suffered up to a 100,000-Pound loss.

Real-time applications’ testing criticality could mean the difference between life and death, in some cases. For example, in the 80s, a radiation therapy machine delivered a lethal dose to six patients, causing the death of 4. Investigators discovered that a software bug was the the main cause of the incident.

Going a step further to take advantage of testing in preventing bugs from ever entering code in the first place, might allow for software maintenance in half the time at half the cost, as one U.S. Department of Defense study found. We will cover this later in the article.

In short, testing properly opens the door to fast, more frequent, and accurate releases.

Great, but …

… there is a catch to proper and effective testing:

Tight Schedule

Testers could go over every piece of the software by hand, running every scenario, on every device, and in every context manually, or they could write automated test cases. In either case, it often consumes too much time that it could create a bottleneck for the entire pipeline.

Yawn!

Testing benefits are not always clear at first glance, and some stakeholders might feel that it’s a drag, as it takes a long-term vision to justify the cost. In addition, most developers find testing mundane, and customers might not appreciate it, considering they don’t see the value outright. It takes discipline to stick to a proper tester’s mindset.

Regression

Humans are prone to mistakes, lapses, or slipping on repetitive tasks, which leads to overlooking issues and re-introduced bugs when retesting. This could mostly be solved by writing automated testing, but team communication is paramount to maintaining a robust test suite.

Laying the Foundation

Now that we have established the importance and annoyances of testing, any professional tester, and even developers, must know the following fundamental testing principles:

  1. Exhaustive testing is not possible
    Most customers I have met expect a “bug-free” solution, whose trust is lost gradually with every issue popping up. Regardless of customer’s expectations in this area, there’s an art in outweighing the risk vs the reward of “seeking” exhaustive testing for the sake of a successful project. Targeting likely sources of the most severe cause of issues for testing could striking the golden balance in this case.
  2. Defect clustering
    The Pareto Principle states that about 80% of the problems are found in 20% of the modules.
  3. Pesticide Paradox
    Using the same pesticide over and over would lead to insects developing resistance, and eventually the pesticide becoming useless. Same goes for tests: running the same tests repeatedly reduces their effectiveness in discovering new issues; existing tests need to be reviewed and new tests need to be developed to catch new bugs.
  4. Testing shows the presence of defects
    Testing reduces the probability of undiscovered issues, but it doesn’t prove correctness.
  5. Absence-of-errors fallacy
    A 99% bug-free software might still not satisfy the customer’s needs. Validation is an essential part of testing where the tester validates the software functionality with the customer’s needs. This might be in the form of a UAT testing activity, for example.
  6. Early testing
    The earlier the testing starts, the cheaper it is to fix. Testing could start as early as the requirements phase.
  7. Testing is context dependent
    Different software require different test steps, procedure, methodologies … etc. For example, testing a safety-critical system is different from an e-commerce website.

Now that we have gone through a quick general discussion, in the next part of the article, we will breakdown the different parts of CRM and why they are a source of headache when it comes to testing.

The post Testing Dynamics CRM – The Discipline | Capsule Series appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/12/testing-dynamics-crm-discipline/feed 0 260
Connect to Dynamics CRM in Node.js http://blog.yagasoft.com/2018/09/connect-dynamics-crm-node?utm_source=rss&utm_medium=rss&utm_campaign=connect-dynamics-crm-node http://blog.yagasoft.com/2018/09/connect-dynamics-crm-node#respond Sun, 02 Sep 2018 11:20:28 +0000 http://blog.yagasoft.com/?p=237 There are a couple of ways that we can authenticate with a CRM deployment: Active Directory (AD), Claims, and OAuth. Finding a single library that can easily handle all three in Node.js was a...

The post Connect to Dynamics CRM in Node.js appeared first on Yagasoft Blog.

]]>
There are a couple of ways that we can authenticate with a CRM deployment: Active Directory (AD), Claims, and OAuth. Finding a single library that can easily handle all three in Node.js was a bit of a challenge. Installing multiple libraries, with different methods of usage, is too much hassle for such a straightforward purpose, in my opinion.

The research

To connect to CRM using AD, I tried httpntlm library, and it worked right away without any issues. However, i faced a lot of issues with OAuth; mainly caused by outdated guides on the Internet.

Previously, I worked mainly with Google’s APIs when it came to OAuth, so it was new territory for me working with Azure. So the first step I did was to try the well-known ADAL.js library. It worked fine in a web app with a proper front end, but in my case, I wanted to connect server-to-server. Try as I might, it never worked, as expected as nearly all guides assume there is an interface for the user.

Stumbling upon this article by Lucas: link, I went back to the basics by opting to do it by hand using basic Node built-in functions.

The solution

I followed his steps for the most part, but I wanted to simplify things even more by automatically acquiring the tokenendpoint. The endpoint requires the tenant ID, which can be found by accessing https://login.windows.net/{xyz.onmicrosoft.com}/.well-known/openid-configuration, after replacing xyz.onmicrosoft.com with the domain of the users.

I will add the option to specify the tenant ID in the configuration, for when the above causes an issue I didn’t foresee.

Using the knowledge acquired above, I created a Node.js library that can do the intended job, for AD and OAuth at least.

Installation

Run the following command in your app’s CLI:

npm i node-dcrm-service

The following imports cover the exposed types in this module:

1
import { CrmService, CrmResponse, CrmConnectionConfig, CrmO365ConnectionConfig, CrmAdConnectionConfig } from "node-dcrm-service";

Configuration

Common parameters

1
2
3
{
}

AD parameters

To authenticate with AD, in addition to the above parameters, all you need is the username, password, and domain.

1
2
3
4
5
6
{
    username: "testuser@testorg.onmicrosoft.com",
    password: "password",
    domain: "domain"
}

OAuth parameters

To authenticate with OAuth, you will need a few more parameters:

  1. tenant: the Azure tenant
  2. appId: Application ID in Azure Active Directory
  3. clientId: the Client Secret created in the application above
1
2
3
4
5
6
7
8
9
{
    webApiHost: 'testorg.api.crm.dynamics.com',
    tenant: 'testorg.onmicrosoft.com',
    username: "testuser@testorg.onmicrosoft.com",
    password: "password",
    appId: "16cd08d5-b6f1-475e-90a3-d40d83e26bbc",
    clientId: "Ao+cz9J6MNe/tyizLZR5ili3Oth/vBoZzTr5DqS6r+o="
}

Refer to the following page for more detailed steps on how to acquire the above OAuth parameters: link.

Initialisation

The parameters defined above are passed to the right configuration constructor first:

1
2
3
4
// OAuth
const config = new CrmO365ConnectionConfig(parameters);
// AD
const config = new CrmAdConnectionConfig(parameters);

Next, construct and initialise the service:

1
2
const crmService = new CrmService(config);
crmService.initialise();

Make CRM requests

The service supports the following HTTP verbs: GET, POST, PUT, PATCH, and DELETE.

To make requests to CRM:

1
2
crmService.then(v => crmService.get("WhoAmI()")
    .then(r => console.log(r.body.UserId)));

Contribution

If you would like to contribute to the project, please clone this repository: link.

The post Connect to Dynamics CRM in Node.js appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/09/connect-dynamics-crm-node/feed 0 237
Dynamics CRM Development Tools http://blog.yagasoft.com/2018/07/dynamics-crm-development-tools?utm_source=rss&utm_medium=rss&utm_campaign=dynamics-crm-development-tools http://blog.yagasoft.com/2018/07/dynamics-crm-development-tools#comments Fri, 27 Jul 2018 01:15:50 +0000 http://blog.yagasoft.com/?p=188 The following table summarises the tools I found most useful, with a link to download them if interested. (scroll to the right for a URL to download the tool) 

The post Dynamics CRM Development Tools appeared first on Yagasoft Blog.

]]>
The following table summarises the tools I found most useful, with a link to download them if interested.

(scroll to the right for a URL to download the tool)

The post Dynamics CRM Development Tools appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/07/dynamics-crm-development-tools/feed 2 188
Dynamics CRM Online Deployment and Administration http://blog.yagasoft.com/2018/04/dynamics-crm-online?utm_source=rss&utm_medium=rss&utm_campaign=dynamics-crm-online http://blog.yagasoft.com/2018/04/dynamics-crm-online#comments Mon, 09 Apr 2018 11:03:04 +0000 http://www.yagasoft.com/?p=135 This session discusses the difference between Dynamics CRM On-premises and Online, and the administration of the Online version.

The post Dynamics CRM Online Deployment and Administration appeared first on Yagasoft Blog.

]]>
This session discusses the difference between Dynamics CRM On-premises and Online, and the administration of the Online version.

The post Dynamics CRM Online Deployment and Administration appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/04/dynamics-crm-online/feed 1 135
Dynamics CRM Installation http://blog.yagasoft.com/2018/04/dynamics-crm-2016-installation?utm_source=rss&utm_medium=rss&utm_campaign=dynamics-crm-2016-installation http://blog.yagasoft.com/2018/04/dynamics-crm-2016-installation#comments Mon, 09 Apr 2018 09:45:04 +0000 http://www.yagasoft.com/?p=132 This session goes over the on-premises deployment of Dynamics CRM.

The post Dynamics CRM Installation appeared first on Yagasoft Blog.

]]>
This session goes over the on-premises deployment of Dynamics CRM.

The post Dynamics CRM Installation appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/04/dynamics-crm-2016-installation/feed 1 132
Dynamics CRM 2016 Installation – Short Version http://blog.yagasoft.com/2018/04/dynamics-crm-2016-installation-short-version?utm_source=rss&utm_medium=rss&utm_campaign=dynamics-crm-2016-installation-short-version http://blog.yagasoft.com/2018/04/dynamics-crm-2016-installation-short-version#respond Mon, 09 Apr 2018 09:34:14 +0000 http://www.yagasoft.com/?p=128 This is a sped-up tutorial of how to install Dynamics CRM 2016 On-premises. The audio is in Arabic.

The post Dynamics CRM 2016 Installation – Short Version appeared first on Yagasoft Blog.

]]>
This is a sped-up tutorial of how to install Dynamics CRM 2016 On-premises. The audio is in Arabic.

The post Dynamics CRM 2016 Installation – Short Version appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/04/dynamics-crm-2016-installation-short-version/feed 0 128
Project Service – Overview http://blog.yagasoft.com/2018/04/project-service-overview?utm_source=rss&utm_medium=rss&utm_campaign=project-service-overview http://blog.yagasoft.com/2018/04/project-service-overview#respond Mon, 09 Apr 2018 08:45:59 +0000 http://www.yagasoft.com/?p=125 This session is an overview of Microsoft’s new solution for “project management” from within CRM. The audio is in Arabic.

The post Project Service – Overview appeared first on Yagasoft Blog.

]]>
This session is an overview of Microsoft’s new solution for “project management” from within CRM. The audio is in Arabic.

The post Project Service – Overview appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/04/project-service-overview/feed 0 125
Web API Basics http://blog.yagasoft.com/2018/04/web-api-basics?utm_source=rss&utm_medium=rss&utm_campaign=web-api-basics http://blog.yagasoft.com/2018/04/web-api-basics#respond Mon, 09 Apr 2018 08:34:26 +0000 http://www.yagasoft.com/?p=122 In this session, I go over the basics of Web API. The audio is in Arabic.

The post Web API Basics appeared first on Yagasoft Blog.

]]>
In this session, I go over the basics of Web API. The audio is in Arabic.

The post Web API Basics appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/04/web-api-basics/feed 0 122
Angular 5 – Quick Intro http://blog.yagasoft.com/2018/04/angular-5-quick-intro?utm_source=rss&utm_medium=rss&utm_campaign=angular-5-quick-intro http://blog.yagasoft.com/2018/04/angular-5-quick-intro#respond Mon, 09 Apr 2018 07:24:16 +0000 http://www.yagasoft.com/?p=117 This session introduces the least required Angular concepts needed to create a functional app. The audio is in Arabic.

The post Angular 5 – Quick Intro appeared first on Yagasoft Blog.

]]>
This session introduces the least required Angular concepts needed to create a functional app. The audio is in Arabic.

The post Angular 5 – Quick Intro appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/04/angular-5-quick-intro/feed 0 117
Dynamics CRM Crash Course http://blog.yagasoft.com/2018/04/dynamics-crm-crash-course-completed?utm_source=rss&utm_medium=rss&utm_campaign=dynamics-crm-crash-course-completed http://blog.yagasoft.com/2018/04/dynamics-crm-crash-course-completed#respond Sun, 08 Apr 2018 15:08:03 +0000 http://www.yagasoft.com/?p=112 I have finished uploading session videos as part of a short series (in the Arabic language only) about Dynamics CRM. The series introduces CRM to developers, allowing them to quickly start producing solutions in...

The post Dynamics CRM Crash Course appeared first on Yagasoft Blog.

]]>
I have finished uploading session videos as part of a short series (in the Arabic language only) about Dynamics CRM. The series introduces CRM to developers, allowing them to quickly start producing solutions in the shortest amount of time.

The sessions cover the essentials in the following:

  1. Business
  2. Configuration
  3. Customisation
  4. Extension

Click here to get access to the series playlist on YouTube.

The post Dynamics CRM Crash Course appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/04/dynamics-crm-crash-course-completed/feed 0 112
Dynamics CRM Crash Course http://blog.yagasoft.com/2018/03/dynamics-crm-crash-course?utm_source=rss&utm_medium=rss&utm_campaign=dynamics-crm-crash-course http://blog.yagasoft.com/2018/03/dynamics-crm-crash-course#respond Wed, 28 Mar 2018 11:52:15 +0000 http://www.yagasoft.com/?p=101 I have started uploading session videos as part of a short series (in the Arabic language only) about Dynamics CRM. The series introduces CRM to developers, allowing them to quickly start producing solutions in...

The post Dynamics CRM Crash Course appeared first on Yagasoft Blog.

]]>
I have started uploading session videos as part of a short series (in the Arabic language only) about Dynamics CRM. The series introduces CRM to developers, allowing them to quickly start producing solutions in the shortest amount of time.

The sessions cover the essentials in the following:

  1. Business
  2. Configuration
  3. Customisation
  4. Extension

Click here to get access to the series playlist on YouTube. I will have completed the series by the end of next week.

The post Dynamics CRM Crash Course appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/03/dynamics-crm-crash-course/feed 0 101
Welcome. http://blog.yagasoft.com/2018/01/welcome?utm_source=rss&utm_medium=rss&utm_campaign=welcome http://blog.yagasoft.com/2018/01/welcome#respond Wed, 31 Jan 2018 15:47:27 +0000 http://www.yagasoft.com/?p=1 Welcome to Yagasoft. I am Ahmed el-Sawalhy, a Software Engineer from Egypt. This is a web-site where I can post my thoughts, pet projects, and share knowledge with the community.

The post Welcome. appeared first on Yagasoft Blog.

]]>
Welcome to Yagasoft. I am Ahmed el-Sawalhy, a Software Engineer from Egypt. This is a web-site where I can post my thoughts, pet projects, and share knowledge with the community.

The post Welcome. appeared first on Yagasoft Blog.

]]>
http://blog.yagasoft.com/2018/01/welcome/feed 0 1