PAMU_CDSce 1.1.3
dotnet add package PAMU_CDSce --version 1.1.3
NuGet\Install-Package PAMU_CDSce -Version 1.1.3
<PackageReference Include="PAMU_CDSce" Version="1.1.3" />
paket add PAMU_CDSce --version 1.1.3
#r "nuget: PAMU_CDSce, 1.1.3"
// Install PAMU_CDSce as a Cake Addin #addin nuget:?package=PAMU_CDSce&version=1.1.3 // Install PAMU_CDSce as a Cake Tool #tool nuget:?package=PAMU_CDSce&version=1.1.3
<h1 align="center">Common Data Service (current environment) mock</h1> <h2 align="center"><a href="https://github.com/thygesteffensen/PowerAutomateMockUp">Power Automate Mock-Up</a></h2> <h3 align="center">Battery included mock for Power Automate CDS connector. Using <a href="https://github.com/thygesteffensen/PowerAutomateMockUp">Power Automate Mock-Up</a> as the flow engine and <a href="http://github.com/delegateas/XrmMockup">XrmMockup</a> as Dynamics engine.</h3> <p align="center"> <img alt="Build status" src="https://github.com/thygesteffensen/PAMU_CDS/actions/workflows/release.yml/badge.svg?branch=main"> <a href="https://www.nuget.org/packages/PAMU_CDSce/"> <img alt="Nuget downloads" src="https://img.shields.io/nuget/dt/PAMU_CDSce"> </a> <a href="https://www.nuget.org/packages/PAMU_CDSce/"> <img alt="Nuget version" src="https://img.shields.io/nuget/v/PAMU_CDSce"> </a> <a href="https://www.nuget.org/packages/PAMU_CDSce/"> <img alt="Nuget prerelease version" src="https://img.shields.io/nuget/vpre/PAMU_CDSce"> </a> </p>
This is a full featured mock for the Common Date Service (current environment) connector for Power Automate.
The mock is built using Power Automate Mock-Up as the flow engine and XrmMockup to mock the underlying Dynamics 365 instance.
Getting Started
First of all, upgrade your XrmMockup with version 1.7.1 or higher.
When configuring XrmMockup, add the following to the XrmMockupSettings
(Only supported in XrmMockup365):
MockUpExtensions = new List<IMockUpExtension> {_pamuCds}
Somewhere before the XrmMockup configure step, do the following to setup Power Automate Mock-Up and add PAMU_CDS to the service collection:
var services = new ServiceCollection();
services.AddFlowRunner();
services.AddPamuCds();
var sp = services.BuildServiceProvider();
_pamuCds = sp.GetRequiredService<XrmMockupCdsTrigger>();
_pamuCds.AddFlows(new Uri(System.IO.Path.GetFullPath(@"Workflows")));
That's all. The flows in the folder will be executed like they would on the server and the actions will be triggered from XrmMockup.
Now you can run your unit tests and the action executed in Power Automate flow will also be executed now, against your mock instance.
Download flows
One way to get the flows, is to export the soltuion containing the flows, then unzip and extract the flows to the desired location.
If you are using XrmFramework or if you're using Daxif, you can execute the F#
script availible here.
Depending on the location of the flows, they might have to be included in the .csproj
. If the flows are placed in a directory inside the test project, in a folder named flows
, simply add the following ItemGroup
, to copy the flows when building:
<ItemGroup>
<Content Include="flows\**\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
Configuring
PAMU_CDS can be configured to behave in a certain way. PAMU can also be configured, see here
Do not execute flows
Add the name of the flow description file, to ignore the flow when triggering from flow from XrmMockup.
services.Configure<CdsFlowSettings>(x =>
x.DontExecuteFlows = new[] {"<flow description file name>.json"});
Actions
The focus right now is to create an MVP to use in my bachelor project, thus not all functions will be implemented for the moment. I will later create a description of how to contribute to this project, but not before the assignment have been handed in.
Unsupported actions
As with PAMU, you can add actions using one of the three extension methods
services.AddFlowActionByName<GetMsnWeather>("Get_forecast_for_today_(Metric)");
services.AddFlowActionByApiIdAndOperationsName<Notification>(
"/providers/Microsoft.PowerApps/apis/shared_flowpush",
new []{ "SendEmailNotification", "SendNotification" });
services.AddFlowActionByFlowType<IfActionExecutor>("If");
A more detialed guide is availible at PAMU#Actions.
General
Every call against CDS returns a JSON object with headers and body. Headers will not be generated, as the MVP does not support the use case.
The body will almost be as the real deal, but with minor deviations. They are described below.
Symbol meaning:
- ✔ Action is intended to work 100% as the real thing, bugs might appear
- ❗ Limited functionality. Action will work, but some logic is not implemented, yet
- ❌ Action is not implemented
Create a new record ✔
Delete a record ✔
Executes a changeset request ❗
This action could be implemented using the ExecuteTransactionRequest. However, XrmMockup does support the request and no issue is currently actively tracking this.
This action is not implemented as it works in Power Automate.
CDS actions inside the change set action will be executed. If one of the CDS actions fails, the change set action will fail as well, piggy backing the error from the failing CDS action. Actions following the failing action inside the change set action will not be executed. Changes made in D365 will still exists, meaning it is not a transaction.
This is basically the saem as a scope. The ScopeActionExecutor
is used, to mock the behaviour.
Get a record ❗
This action supports 4 parameters
- Entity name - Table name
- Entity id - row id
- $select
- $expand
3. $select
The select query is rather easy, since it is just are list of strings delimited by a comma, which can easily be converted to a ColumnSet.
4. $expand
The expand query is a bit more complex. It's documentation can be seen here.
Since the input of expand can have different forms, interpreting in can be a bit difficult. You cannot create a simple split string by comma, since this will not divide the odata filters corrext. Instead I have created a parser, similar to ExpressionParser in PAMU, but more simple. At the moment, the Parser does not cover all cases, but it's sufficient enough to cover the base case in the MVP.
The grammer for the parser is:
$expand=something($select=prop1,prop2),something2($select=prop1,prop2;$orderby=prop func;$filter=endswith(subhect,'1'))
<values> ::= <value> *(,<value>)
<value> ::= <string> *(<parameters>)
<parameters> ::= '('<parameter> *(;<paramters>)')'
<paramter> ::= $<string>=(<properties>|<function>)
<properties> ::= <string> *(,<string>)
<function> ::= <string> '('+(<string>)')'
Get file or image content ❌
Action is not implemented and will not be implemented in the near future.
List records ❗
Currently the list records in converted to a QueryExpression, but it should be converted to a FetchXML instead, since FetchXML cover more of the features of Odata than QueryExpression.
Name | Key | Required | Type | Description | |
---|---|---|---|---|---|
✔ | Entity name | entityName | True | string | Choose an option or add your own |
✔ | Select Query | $select | string | Limit the properties returned while retrieving data. | |
❗ | Filter Query | $filter | string | An ODATA filter query to restrict the entries returned (e.g. stringColumn eq 'string' OR numberColumn lt 123). | |
❗ | Order By | $orderby | string | An ODATA orderBy query for specifying the order of entries. | |
❌ | Expand Query | $expand | string | Related entries to include with requested entries (default = none). | |
✔ | Fetch Xml Query | fetchXml | string | Fetch Xml query | |
✔ | Top Count | $top | integer | Total number of entries to retrieve (default = all). | |
❗ | Skip token | $skiptoken | string | The skip token. |
Skip token, as well as Odata.nextLink on response will not be implemented.
Fetch Xml Expression will simple be a FetchExpression
instead of a QueryExpression. The correctness of FetchExpression
will depend on XrmMockup.
Filter Query
The filter query is made in OData in Power Automate. I have written a small Odata parser, which parses the Odata query to a FilterExpression, but not to a full extend.
Every Condition Operator, i.e. eq, ne, lt, is supported for strings, integers, decimals, booleans and null. The functions Startswith, Endswith and substringof is supported, the others are not supported, as they cannot be easily mapped to a FilterExpression.
The CFG in EBNF for the parser is:
or ::= and ('or' or)+
and ::= stm ('and' and)+
stm ::= func | '(' or ')' | attr op val
val ::= func | const
op ::= eq ne ...
attr ::= string
func ::= string '(' params ')'
Order By
Order By is not working as in Power Automate, simply because the QueryExpression does not support ordering of linked entities.
Expand Query
Is not supported at the moment.
Skip token
Not supported.
Perform a bound action ❌
XrmMockup does not support actions. If you want support check support custom action plugins #65.
Perform an unbound action ❌
XrmMockup does not support actions. If you want support check support custom action plugins #65.
Predict ❌
Action is not implemented and will not be implemented in the near future.
Relate records ✔
Unrelate records ✔
Update record ✔
Upload file or image content ❌
Action is not implemented and will not be implemented in the near future.
Trigger
XrmMockupCdsTrigger is a class to trigger a set of flows, based on the Request made to Dynamics. XrmMockupCdsTrigger is built to be used togehter with XrmMockup.
The trigger will apply a filters from the trigger, but only with limited functionality for now.
Code style
The code is written using Riders default C# code style.
Commits are written in conventional commit style, the commit messages are used to determine the version and when to release a new version. The pipeline is hosted on Github and Semantic Release is used.
Installation
Currently the project is still in alpha. To find the packages at nuget.com, you have to check 'Prerelease', before the nuget appears.
You also need XrmMockup to get the full functionality togehter with Dynamics 365 customizations. If you don't use XrmMockup or don't want to, you can provide a mock of IOrganizationService and add it to the service collection.
Tests
Tests are located in the Tests project and they are written using Nunit as test framework.
Contribute
This is my bachelor project and I'm currently not accepting contributions until it have been handed in. Anyway, fell free to drop an issue with a suggestion or improvement.
Credits
Delegate A/S and the team behind XrmMockup.
License
MIT
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET Framework | net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 is compatible. net481 was computed. |
-
.NETFramework 4.6.2
- Microsoft.CrmSdk.CoreAssemblies (>= 9.0.2.29)
- Microsoft.CSharp (>= 4.7.0)
- Microsoft.Extensions.Configuration (>= 5.0.0)
- Microsoft.Extensions.DependencyInjection (>= 5.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 5.0.0)
- Microsoft.Extensions.Options (>= 5.0.0)
- Newtonsoft.Json (>= 13.0.1)
- PowerAutomateMockUp (>= 2.0.0)
- Sprache (>= 2.3.1)
- XrmMockup365 (>= 1.12.1)
-
.NETFramework 4.8
- Microsoft.CrmSdk.CoreAssemblies (>= 9.0.2.29)
- Microsoft.CSharp (>= 4.7.0)
- Microsoft.Extensions.Configuration (>= 5.0.0)
- Microsoft.Extensions.DependencyInjection (>= 5.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 5.0.0)
- Microsoft.Extensions.Options (>= 5.0.0)
- Newtonsoft.Json (>= 13.0.1)
- PowerAutomateMockUp (>= 2.0.0)
- Sprache (>= 2.3.1)
- XrmMockup365 (>= 1.12.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.1.3 | 173 | 5/18/2023 |
1.1.3-patch | 86 | 5/17/2023 |
1.1.3-alpha.1 | 77 | 5/18/2023 |
1.1.2 | 98 | 5/17/2023 |
1.1.2-patch | 77 | 5/17/2023 |
1.1.2-alpha.1 | 76 | 5/17/2023 |
1.1.1 | 148 | 5/15/2023 |
1.1.1-alpha.2 | 78 | 5/15/2023 |
1.1.1-alpha.1 | 77 | 5/15/2023 |
1.1.0 | 98 | 5/15/2023 |
1.1.0-alpha.4 | 79 | 5/15/2023 |
1.1.0-alpha.3 | 80 | 5/15/2023 |
1.1.0-alpha.2 | 92 | 3/7/2023 |
1.1.0-alpha.1 | 92 | 3/7/2023 |
1.0.1 | 388 | 1/31/2021 |
1.0.0 | 350 | 1/30/2021 |
1.0.0-alpha.37 | 168 | 1/31/2021 |
1.0.0-alpha.36 | 161 | 1/30/2021 |
1.0.0-alpha.35 | 160 | 1/29/2021 |
1.0.0-alpha.34 | 161 | 1/29/2021 |
1.0.0-alpha.33 | 168 | 1/28/2021 |
1.0.0-alpha.32 | 155 | 1/28/2021 |
1.0.0-alpha.31 | 164 | 1/28/2021 |
1.0.0-alpha.30 | 163 | 1/28/2021 |
1.0.0-alpha.29 | 171 | 1/28/2021 |
1.0.0-alpha.28 | 151 | 1/28/2021 |
1.0.0-alpha.27 | 173 | 1/23/2021 |
1.0.0-alpha.26 | 200 | 1/21/2021 |
1.0.0-alpha.25 | 210 | 1/21/2021 |
1.0.0-alpha.24 | 198 | 1/21/2021 |
1.0.0-alpha.23 | 169 | 1/19/2021 |
1.0.0-alpha.22 | 179 | 1/19/2021 |
1.0.0-alpha.21 | 170 | 1/19/2021 |
1.0.0-alpha.20 | 221 | 1/16/2021 |
1.0.0-alpha.19 | 157 | 1/16/2021 |
1.0.0-alpha.18 | 158 | 1/16/2021 |
1.0.0-alpha.17 | 166 | 1/16/2021 |
1.0.0-alpha.16 | 177 | 1/16/2021 |
1.0.0-alpha.15 | 183 | 1/16/2021 |
1.0.0-alpha.14 | 209 | 1/14/2021 |
1.0.0-alpha.13 | 217 | 1/14/2021 |
1.0.0-alpha.12 | 166 | 1/13/2021 |
1.0.0-alpha.11 | 171 | 1/13/2021 |
1.0.0-alpha.10 | 206 | 1/13/2021 |
1.0.0-alpha.9 | 159 | 1/12/2021 |
1.0.0-alpha.8 | 191 | 1/12/2021 |
1.0.0-alpha.7 | 222 | 12/21/2020 |
1.0.0-alpha.6 | 225 | 12/21/2020 |
1.0.0-alpha.5 | 230 | 12/21/2020 |
1.0.0-alpha.4 | 198 | 12/8/2020 |
1.0.0-alpha.3 | 251 | 12/6/2020 |