From 57ba6ace4031296e52b9f0e19ca8bd5db12804f0 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Wed, 8 Apr 2020 15:20:49 +0200 Subject: [PATCH 001/950] Create devenv-directives-in-al.md --- .../developer/devenv-directives-in-al.md | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 dev-itpro/developer/devenv-directives-in-al.md diff --git a/dev-itpro/developer/devenv-directives-in-al.md b/dev-itpro/developer/devenv-directives-in-al.md new file mode 100644 index 0000000000..7b43019310 --- /dev/null +++ b/dev-itpro/developer/devenv-directives-in-al.md @@ -0,0 +1,67 @@ +--- +title: "Directives in AL" +description: +author: SusanneWindfeldPedersen +ms.custom: na +ms.date: 04/08/2020 +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +ms.author: solsen +--- + +# Directives in AL + +Anything can be made conditional, also table fields. Symbols can be defined in the manifest or in the beginning of a source file. There is currently no built-in symbols. + +There will also be a server side check-in that create ParseOptions from manifest and it when parsing up syntax trees. + +The following AL preprocessor directives are supported: + +|Preprocessor directive |Description | +|-----------------------|------------| +|#elif | | +|#endif | | +|#region | | +|#endregion | | +|#define | | +|#undef | | +|#pragma | | +|#warning | | +|#disable | | +|#restore | | +|#enable | | + +## Examples + +### Region support + +#region Ugly stuff - not written by me, of course + procedure UglyCode() + begin + // No one should look at this + end; +#endregion + +## Warning suppression + +table 50110 MyTable +{ + fields + { +#pragma warning disable AL0468 + field(1; TableWithLongIdentifierThatExceedsOurMax; Integer) { } +#pragma warning restore + } +} + +## Conditional code + +#if DEBUG + trigger OnOpenPage() + begin + Message('Only in debug versions'); + end; +#endif + From d361b0c3fb9b8ed752488e01021df476a2ba3aac Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Wed, 8 Apr 2020 15:44:02 +0200 Subject: [PATCH 002/950] Update devenv-directives-in-al.md --- dev-itpro/developer/devenv-directives-in-al.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-directives-in-al.md b/dev-itpro/developer/devenv-directives-in-al.md index 7b43019310..c63fcaa106 100644 --- a/dev-itpro/developer/devenv-directives-in-al.md +++ b/dev-itpro/developer/devenv-directives-in-al.md @@ -17,11 +17,13 @@ Anything can be made conditional, also table fields. Symbols can be defined in t There will also be a server side check-in that create ParseOptions from manifest and it when parsing up syntax trees. -The following AL preprocessor directives are supported: +The following AL preprocessor directives are supported. For examples, see the [Examples](devenv-directives-in-al-md#Examples) section below. |Preprocessor directive |Description | |-----------------------|------------| -|#elif | | +|#if | | +|#else | | +|#elif | Combines `else` and `if`. If `#elif` is `true` the compiler evaluates all code between `#elif` and the next conditional directive.| |#endif | | |#region | | |#endregion | | From 5ccad52436e0fdabce2a14fce6c9d68195735358 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 15 Apr 2020 11:26:41 +0200 Subject: [PATCH 003/950] fix --- .../properties/devenv-tabletype-property.md | 24 ++++++++++++++----- dev-itpro/performance/performance-onprem.md | 6 +++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/dev-itpro/developer/properties/devenv-tabletype-property.md b/dev-itpro/developer/properties/devenv-tabletype-property.md index 686e24b07a..c24a23d3d5 100644 --- a/dev-itpro/developer/properties/devenv-tabletype-property.md +++ b/dev-itpro/developer/properties/devenv-tabletype-property.md @@ -21,12 +21,12 @@ Specifies the table type. |Value|Description| |-----------|-----------------| -|**Normal**|Specifies the table as a normal table in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database. This is the default value.| +|**Normal**|Specifies the table as a normal table in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database. This value is the default.| |**CDS**|Specifies the table as an integration table for integrating [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] with [!INCLUDE[crm](../includes/crm_md.md)]. The table is typically based on an entity in [!INCLUDE[crm](../includes/crm_md.md)], such as the Accounts entity.| -|**ExternalSQL**|Specifies the table as a table or view in SQL Server that is not in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database.| -|**Temporary**|Specifies the table as a temporary table in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database. This table type is not synchronized.| -|**Exchange**|This is for internal use only.| -|**MicrosoftGraph**|This is for internal use only.| +|**ExternalSQL**|Specifies the table as a table or view in SQL Server that isn't in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database.| +|**Temporary**|Specifies the table as a temporary table in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database. This table type isn't synchronized.| +|**Exchange**|For internal use only.| +|**MicrosoftGraph**|For for internal use only.| ## Syntax @@ -41,8 +41,20 @@ TableType = CDS; > We advise against creating tables of type CDS manually. Instead, use the integration mapping functionality. + +Marking a table as **Temporary** is the same as: + +- Setting all records in the table as "Temporary". See [Temporary Property](devenv-temporary-property.md). +- Setting "SourceTableTemporary" on all pages that use the table. See [SourceTableTemporary Property](devenv-sourcetabletemporary-property.md). + +Temporary tables aren't synchronized to the SQL database, so they don't follow the same rules about making destructive changes. + ## See Also -[Properties](devenv-properties.md) +[Properties](devenv-properties.md) +[SourceTableTemporary Property](devenv-sourcetabletemporary-property.md) +[Temporary Property](devenv-temporary-property.md) + + diff --git a/dev-itpro/performance/performance-onprem.md b/dev-itpro/performance/performance-onprem.md index 8b9714dfe6..8c8cf7fb12 100644 --- a/dev-itpro/performance/performance-onprem.md +++ b/dev-itpro/performance/performance-onprem.md @@ -107,9 +107,11 @@ These articles can be useful when troubleshooting database performance issues: - [Configuring Query Hints for Optimizing SQL Server Performance with Business Central](../administration/sql-server-query-hints.md) - [Troubleshooting: Using Query Store to Monitor Query Performance in Business Central](../administration/troubleshoot-query-performance-using-query-store.md) -#### Performance of bacpac generation +#### Performance of BACPAC generation -The sqlpackage is the command-line tool used to generate bacpac/dacpac files. The February 2019 update of sqlpackage solved a significant schema-compare performance issue that occurred when generating scripts. Make sure you use **version 18.1 or later** if you experience issues in bacpac generation performance. +The sqlpackage is the command-line tool used to generate BACPAC/DACPAC files. The February 2019 update of sqlpackage solved a significant schema-compare performance issue that occurred when generating scripts. Make sure you use **version 18.1 or later** if you experience issues in BACPAC generation performance. + +You can also limit the amount of SQL schema to restore from a BACPAC. On tables used only with temporary record variables and pages, set the [TableType property](../developer/properties/devenv-tabletype-property.md) to **Temporary**. #### Performance impact on setting up CDC on SQL Server From 1e051fcf3c569e2bbd16d9e1ed5ecef7e3b00c51 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 16 Apr 2020 08:57:58 +0200 Subject: [PATCH 004/950] Update devenv-tabletype-property.md --- dev-itpro/developer/properties/devenv-tabletype-property.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/developer/properties/devenv-tabletype-property.md b/dev-itpro/developer/properties/devenv-tabletype-property.md index c24a23d3d5..6fb959f29a 100644 --- a/dev-itpro/developer/properties/devenv-tabletype-property.md +++ b/dev-itpro/developer/properties/devenv-tabletype-property.md @@ -44,7 +44,7 @@ TableType = CDS; Marking a table as **Temporary** is the same as: -- Setting all records in the table as "Temporary". See [Temporary Property](devenv-temporary-property.md). +- Set all Record variables in AL code to "Temporary". See [Temporary Property](devenv-temporary-property.md). - Setting "SourceTableTemporary" on all pages that use the table. See [SourceTableTemporary Property](devenv-sourcetabletemporary-property.md). Temporary tables aren't synchronized to the SQL database, so they don't follow the same rules about making destructive changes. From c74232da67d84c94ba1c217aa0fc93c48002a43d Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 16 Apr 2020 09:12:04 +0200 Subject: [PATCH 005/950] Update devenv-tabletype-property.md --- dev-itpro/developer/properties/devenv-tabletype-property.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/properties/devenv-tabletype-property.md b/dev-itpro/developer/properties/devenv-tabletype-property.md index 6fb959f29a..5ae1bc288b 100644 --- a/dev-itpro/developer/properties/devenv-tabletype-property.md +++ b/dev-itpro/developer/properties/devenv-tabletype-property.md @@ -41,10 +41,12 @@ TableType = CDS; > We advise against creating tables of type CDS manually. Instead, use the integration mapping functionality. - + +### Temporary tables + Marking a table as **Temporary** is the same as: -- Set all Record variables in AL code to "Temporary". See [Temporary Property](devenv-temporary-property.md). +- Setting all Record variables in AL code to "Temporary". See [Temporary Property](devenv-temporary-property.md). - Setting "SourceTableTemporary" on all pages that use the table. See [SourceTableTemporary Property](devenv-sourcetabletemporary-property.md). Temporary tables aren't synchronized to the SQL database, so they don't follow the same rules about making destructive changes. From c8e070163532a4a8a18291a2b039ae0f5108121a Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 16 Apr 2020 09:34:59 +0200 Subject: [PATCH 006/950] Update devenv-tabletype-property.md --- dev-itpro/developer/properties/devenv-tabletype-property.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dev-itpro/developer/properties/devenv-tabletype-property.md b/dev-itpro/developer/properties/devenv-tabletype-property.md index 5ae1bc288b..801810e0c2 100644 --- a/dev-itpro/developer/properties/devenv-tabletype-property.md +++ b/dev-itpro/developer/properties/devenv-tabletype-property.md @@ -24,7 +24,7 @@ Specifies the table type. |**Normal**|Specifies the table as a normal table in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database. This value is the default.| |**CDS**|Specifies the table as an integration table for integrating [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] with [!INCLUDE[crm](../includes/crm_md.md)]. The table is typically based on an entity in [!INCLUDE[crm](../includes/crm_md.md)], such as the Accounts entity.| |**ExternalSQL**|Specifies the table as a table or view in SQL Server that isn't in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database.| -|**Temporary**|Specifies the table as a temporary table in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database. This table type isn't synchronized.| +|**Temporary**|Specifies the table as an in-memory only table in the [!INCLUDE[server](../includes/server.md)]. This table type is not synchronized to the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database.| |**Exchange**|For internal use only.| |**MicrosoftGraph**|For for internal use only.| @@ -51,6 +51,9 @@ Marking a table as **Temporary** is the same as: Temporary tables aren't synchronized to the SQL database, so they don't follow the same rules about making destructive changes. +If you change an existing table from **Normal** to **Temporary**, the table is abandoned in SQL Server. If the table contains data, you'll have to use the ForceSync mode when synchronizing the extension with the database. + + ## See Also [Properties](devenv-properties.md) From cb33d742cac03ea8512f7020da82aec672bc2a60 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 16 Apr 2020 09:37:39 +0200 Subject: [PATCH 007/950] Update devenv-tabletype-property.md --- dev-itpro/developer/properties/devenv-tabletype-property.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/developer/properties/devenv-tabletype-property.md b/dev-itpro/developer/properties/devenv-tabletype-property.md index 801810e0c2..83614ea7a7 100644 --- a/dev-itpro/developer/properties/devenv-tabletype-property.md +++ b/dev-itpro/developer/properties/devenv-tabletype-property.md @@ -51,7 +51,7 @@ Marking a table as **Temporary** is the same as: Temporary tables aren't synchronized to the SQL database, so they don't follow the same rules about making destructive changes. -If you change an existing table from **Normal** to **Temporary**, the table is abandoned in SQL Server. If the table contains data, you'll have to use the ForceSync mode when synchronizing the extension with the database. +If you change an existing table from **Normal** to **Temporary**, the table is dropped in SQL Server. If the table contains data, you'll have to use the ForceSync mode when synchronizing the extension with the database. ## See Also From 297f540402aef19af96b8030dc428d105b916eac Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 16 Apr 2020 11:41:24 +0200 Subject: [PATCH 008/950] Update devenv-tabletype-property.md --- dev-itpro/developer/properties/devenv-tabletype-property.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/developer/properties/devenv-tabletype-property.md b/dev-itpro/developer/properties/devenv-tabletype-property.md index 83614ea7a7..c908d632a4 100644 --- a/dev-itpro/developer/properties/devenv-tabletype-property.md +++ b/dev-itpro/developer/properties/devenv-tabletype-property.md @@ -51,7 +51,7 @@ Marking a table as **Temporary** is the same as: Temporary tables aren't synchronized to the SQL database, so they don't follow the same rules about making destructive changes. -If you change an existing table from **Normal** to **Temporary**, the table is dropped in SQL Server. If the table contains data, you'll have to use the ForceSync mode when synchronizing the extension with the database. +If you change an existing table from **Normal** to **Temporary**, the table will be deleted from the database when you synchronize the extension. If the table contains data, you'll have to use the ForceSync mode. ## See Also From b9d20a5f7ad53e18ff6e808f4fca7469a438ab6d Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 16 Apr 2020 11:53:36 +0200 Subject: [PATCH 009/950] Update devenv-tabletype-property.md --- dev-itpro/developer/properties/devenv-tabletype-property.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/properties/devenv-tabletype-property.md b/dev-itpro/developer/properties/devenv-tabletype-property.md index c908d632a4..61038fd839 100644 --- a/dev-itpro/developer/properties/devenv-tabletype-property.md +++ b/dev-itpro/developer/properties/devenv-tabletype-property.md @@ -24,7 +24,7 @@ Specifies the table type. |**Normal**|Specifies the table as a normal table in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database. This value is the default.| |**CDS**|Specifies the table as an integration table for integrating [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] with [!INCLUDE[crm](../includes/crm_md.md)]. The table is typically based on an entity in [!INCLUDE[crm](../includes/crm_md.md)], such as the Accounts entity.| |**ExternalSQL**|Specifies the table as a table or view in SQL Server that isn't in the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database.| -|**Temporary**|Specifies the table as an in-memory only table in the [!INCLUDE[server](../includes/server.md)]. This table type is not synchronized to the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database.| +|**Temporary**|Specifies the table as an in-memory only table in the [!INCLUDE[server](../includes/server.md)]. This table type isn't synchronized to the [!INCLUDE[d365fin_long_md](../includes/d365fin_long_md.md)] database.| |**Exchange**|For internal use only.| |**MicrosoftGraph**|For for internal use only.| @@ -51,7 +51,7 @@ Marking a table as **Temporary** is the same as: Temporary tables aren't synchronized to the SQL database, so they don't follow the same rules about making destructive changes. -If you change an existing table from **Normal** to **Temporary**, the table will be deleted from the database when you synchronize the extension. If the table contains data, you'll have to use the ForceSync mode. +You can change an existing table from **Normal** to **Temporary**. But the table will be deleted from the database when you synchronize the extension. If the table contains data, you'll have to use the ForceSync mode. ## See Also From 8bda140f78c9e88cec1b33f9991ad89aed9269de Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 17 Apr 2020 06:00:09 +0200 Subject: [PATCH 010/950] Update configure-server-instance.md --- dev-itpro/administration/configure-server-instance.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 80859179f3..5ba65ab9fd 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -168,6 +168,8 @@ The following table describes fields on the **Client Services** tab in the [!INC |Enable SSL|SOAPServicesSSLEnabled|Specifies whether SSL \(https\) is enabled for the SOAP web service port. For more information, see [Using Security Certificates with Business Central On-Premises](../deployment/implement-security-certificates-production-environment.md).

Default: Not enabled
Dynamically Updatable: No| |Max Connections|SOAPMaxConnections|Specifies the maximum number of simultaneous SOAP requests on the server instance (for all tenants). When the limit is exceeded, an error occurs. If you don'tt want a limit, set the value **0**.

Default: 0
Dynamically Updatable: Yes| |Max Connections Per Tenant|SOAPMaxConnectionsPerTenant|Specifies the maximum number of simultaneous SOAP requests per tenant. When the limit is exceeded, an error occurs. If you do not want a limit, set the value **0**.

Default: 0
Dynamically Updatable: Yes| +|Max Concurrent Requests|SOAPMaxConcurrentRequests|Specifies the maximum number of concurrent SOAP connections per tenant that the server instance can actively process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|Max Queued Requests|SOAPRequestQueueSize|Specifies the maximum number of outstanding SOAP connections per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |Max Message Size|SOAPServicesMaxMsgSize|Specifies the maximum permitted size of a SOAP web services request, in kilobytes. When a request exceeds this limit, a 413: Request Entity Too Large error occurs.

**Important:** This setting also pertains to OData web services.

Default: 65536
Dynamically Updatable: No| |Port|SOAPServicesPort|The listening HTTP port for SOAP web services.

Valid range: 1 - 65535
Default: 7047
Dynamically Updatable: No| |SOAP Base URL|PublicSOAPBaseUrl|Specifies the root of the URLs that are used to access SOAP web services. For example, you can change the value if you want to change the externally facing endpoint.

The base URL must have the following syntax:

http\[s\]://*hostname*:*port*/*instance*/WS/

This field maps to the `PublicSOAPBaseUrl` setting in the CustomSettings.config file for the [!INCLUDE[server](../developer/includes/server.md)] instance.

Default: The SOAP URL for the server instance
Dynamically Updatable: No| @@ -186,11 +188,15 @@ If you do not want a timeout, set the value to **MaxValue**.

Default: |Enable SSL|ODataServicesSSLEnabled|Specifies whether SSL \(https\) is enabled for the OData web service port. For more information, see [Using Security Certificates with Business Central On-Premises](../deployment/implement-security-certificates-production-environment.md).

Default: Not enabled
Dynamically Updatable: No| |Enable V3 Endpoint|ODataServicesV3EndpointEnabled|Specifies whether the ODataV3 service endpoint will be enabled.

Default: Enabled
Dynamically Updatable: No| |Enable V4 Endpoint|ODataServicesV4EndpointEnabled|Specifies whether the ODataV4 service endpoint will be enabled.

Default: Enabled
Dynamically Updatable: No| -|Max Connections|ODataMaxConnections|Specifies the maximum number of simultaneous OData requests on the server instance (for all tenants). When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value 0.

OData requests consume server instance resources, which can affect the performance of the clients if the number of requests gets too large. This setting enables you to control the resources allocated for OData requests.

Default: 0
Dynamically Updatable: Yes| +|Max Connections|ODataMaxConnections|Specifies the maximum number of simultaneous OData requests on the server instance (for all tenants). When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

OData requests consume server instance resources, which can affect the performance of the clients if the number of requests gets too large. This setting enables you to control the resources allocated for OData requests.

Default: 0
Dynamically Updatable: Yes| |Max Connections Per Tenant|ODataMaxConnectionsPerTenant|Specifies the maximum number of simultaneous OData requests per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value 0.

If the server isn't configured for multitenancy or only has a single tenant, then this setting does the same as the **Max Connections** (ODataMaxConnections) setting.

OData requests consume server instance resources and can affect the performance of the clients if the number of requests gets too large. This setting enables you to control the resources allocated for OData requests.

Default: 0
Dynamically Updatable: Yes| |Max Page Size|ODataServicesMaxPageSize|Specifies the maximum number of entities returned per page of OData results. For more information, see [Server-Driven Paging in OData Web Services](../webservices/Server-Driven-Paging-in-OData-Web-Services.md).

Default: 1000
Dynamically Updatable: No| |OData Base URL|PublicODataBaseUrl|Specifies the root of the URLs that are used to access OData web services. For example, you can change the value if you want to change the externally facing endpoint.

The base URL must have the following syntax:

http\[s\]://*hostname*:*port*/*instance*/OData/

This field maps to the `PublicODataBaseUrl` setting in the CustomSettings.config file for the [!INCLUDE[server](../developer/includes/server.md)] instance.

Default: The OData URL for the server instance
Dynamically Updatable: No| |Port|ODataServicesPort|The listening HTTP port for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] OData web services.

Valid range: 1 - 65535
Default: 7048
Dynamically Updatable: No| +|V3 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of concurrent OData V3 connections per tenant that the server instance can actively process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V3 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of outstanding OData V3 connectons per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of concurrent OData V4 connections per tenant that the server instance can actively process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of outstanding OData V4 connections per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |Timeout|ODataServicesOperationTimeout |Specifies the maximum amount of time that the server instance can allocate to a single OData request. When the limit is exceeded, a 408 (Request Timeout) error occurs.

If you don't want a limit, set the value to `MaxValue`.

Time format: hh:mm:ss
Default: 00:08:00
Dynamically Updatable: Yes| > [!IMPORTANT] From 8f6cfefb514190ef3333b6f0b751755c82f96a58 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 17 Apr 2020 13:42:13 +0200 Subject: [PATCH 011/950] Update configure-server-instance.md --- dev-itpro/administration/configure-server-instance.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 5ba65ab9fd..be2e2946fd 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -195,8 +195,8 @@ If you do not want a timeout, set the value to **MaxValue**.

Default: |Port|ODataServicesPort|The listening HTTP port for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] OData web services.

Valid range: 1 - 65535
Default: 7048
Dynamically Updatable: No| |V3 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of concurrent OData V3 connections per tenant that the server instance can actively process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |V3 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of outstanding OData V3 connectons per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|V4 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of concurrent OData V4 connections per tenant that the server instance can actively process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|V4 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of outstanding OData V4 connections per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of OData V4 reqests per tenant that the server instance can actively process at the same time. Request that exceed the limit will wait in the queue until a slot becomes available. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of OData V4 requests per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |Timeout|ODataServicesOperationTimeout |Specifies the maximum amount of time that the server instance can allocate to a single OData request. When the limit is exceeded, a 408 (Request Timeout) error occurs.

If you don't want a limit, set the value to `MaxValue`.

Time format: hh:mm:ss
Default: 00:08:00
Dynamically Updatable: Yes| > [!IMPORTANT] From f52d4451d17176ec0d129083a1a1965c750cbdf9 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 17 Apr 2020 14:13:56 +0200 Subject: [PATCH 012/950] Update configure-server-instance.md --- dev-itpro/administration/configure-server-instance.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index be2e2946fd..e3915485a2 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -193,10 +193,10 @@ If you do not want a timeout, set the value to **MaxValue**.

Default: |Max Page Size|ODataServicesMaxPageSize|Specifies the maximum number of entities returned per page of OData results. For more information, see [Server-Driven Paging in OData Web Services](../webservices/Server-Driven-Paging-in-OData-Web-Services.md).

Default: 1000
Dynamically Updatable: No| |OData Base URL|PublicODataBaseUrl|Specifies the root of the URLs that are used to access OData web services. For example, you can change the value if you want to change the externally facing endpoint.

The base URL must have the following syntax:

http\[s\]://*hostname*:*port*/*instance*/OData/

This field maps to the `PublicODataBaseUrl` setting in the CustomSettings.config file for the [!INCLUDE[server](../developer/includes/server.md)] instance.

Default: The OData URL for the server instance
Dynamically Updatable: No| |Port|ODataServicesPort|The listening HTTP port for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] OData web services.

Valid range: 1 - 65535
Default: 7048
Dynamically Updatable: No| -|V3 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of concurrent OData V3 connections per tenant that the server instance can actively process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V3 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of concurrent OData V3 connections per tenant that the server instance can process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |V3 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of outstanding OData V3 connectons per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|V4 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of OData V4 reqests per tenant that the server instance can actively process at the same time. Request that exceed the limit will wait in the queue until a slot becomes available. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|V4 Max Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of OData V4 requests per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of OData V4 reqests per tenant that the server instance can actively process at the same time. Requests that exceed the limit will wait in the queue until a slot becomes available. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of pending OData V4 requests per tenant, including requests that are being processed and those waiting to be processed. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |Timeout|ODataServicesOperationTimeout |Specifies the maximum amount of time that the server instance can allocate to a single OData request. When the limit is exceeded, a 408 (Request Timeout) error occurs.

If you don't want a limit, set the value to `MaxValue`.

Time format: hh:mm:ss
Default: 00:08:00
Dynamically Updatable: Yes| > [!IMPORTANT] From dd32032e0972404561522f2bf9140be2d9b5e979 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 17 Apr 2020 15:06:37 +0200 Subject: [PATCH 013/950] Update configure-server-instance.md --- .../administration/configure-server-instance.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index e3915485a2..09fc6fe996 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -168,8 +168,8 @@ The following table describes fields on the **Client Services** tab in the [!INC |Enable SSL|SOAPServicesSSLEnabled|Specifies whether SSL \(https\) is enabled for the SOAP web service port. For more information, see [Using Security Certificates with Business Central On-Premises](../deployment/implement-security-certificates-production-environment.md).

Default: Not enabled
Dynamically Updatable: No| |Max Connections|SOAPMaxConnections|Specifies the maximum number of simultaneous SOAP requests on the server instance (for all tenants). When the limit is exceeded, an error occurs. If you don'tt want a limit, set the value **0**.

Default: 0
Dynamically Updatable: Yes| |Max Connections Per Tenant|SOAPMaxConnectionsPerTenant|Specifies the maximum number of simultaneous SOAP requests per tenant. When the limit is exceeded, an error occurs. If you do not want a limit, set the value **0**.

Default: 0
Dynamically Updatable: Yes| -|Max Concurrent Requests|SOAPMaxConcurrentRequests|Specifies the maximum number of concurrent SOAP connections per tenant that the server instance can actively process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|Max Queued Requests|SOAPRequestQueueSize|Specifies the maximum number of outstanding SOAP connections per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|Max Concurrent Requests|SOAPMaxConcurrentRequests|Specifies the maximum number of SOAP requests per tenant that the server instance can process at the same time. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|Max Queued Requests|SOAPRequestQueueSize|Specifies the maximum number of pending SOAP connections per tenant, including requests being processed and waiting to be processed. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |Max Message Size|SOAPServicesMaxMsgSize|Specifies the maximum permitted size of a SOAP web services request, in kilobytes. When a request exceeds this limit, a 413: Request Entity Too Large error occurs.

**Important:** This setting also pertains to OData web services.

Default: 65536
Dynamically Updatable: No| |Port|SOAPServicesPort|The listening HTTP port for SOAP web services.

Valid range: 1 - 65535
Default: 7047
Dynamically Updatable: No| |SOAP Base URL|PublicSOAPBaseUrl|Specifies the root of the URLs that are used to access SOAP web services. For example, you can change the value if you want to change the externally facing endpoint.

The base URL must have the following syntax:

http\[s\]://*hostname*:*port*/*instance*/WS/

This field maps to the `PublicSOAPBaseUrl` setting in the CustomSettings.config file for the [!INCLUDE[server](../developer/includes/server.md)] instance.

Default: The SOAP URL for the server instance
Dynamically Updatable: No| @@ -193,10 +193,10 @@ If you do not want a timeout, set the value to **MaxValue**.

Default: |Max Page Size|ODataServicesMaxPageSize|Specifies the maximum number of entities returned per page of OData results. For more information, see [Server-Driven Paging in OData Web Services](../webservices/Server-Driven-Paging-in-OData-Web-Services.md).

Default: 1000
Dynamically Updatable: No| |OData Base URL|PublicODataBaseUrl|Specifies the root of the URLs that are used to access OData web services. For example, you can change the value if you want to change the externally facing endpoint.

The base URL must have the following syntax:

http\[s\]://*hostname*:*port*/*instance*/OData/

This field maps to the `PublicODataBaseUrl` setting in the CustomSettings.config file for the [!INCLUDE[server](../developer/includes/server.md)] instance.

Default: The OData URL for the server instance
Dynamically Updatable: No| |Port|ODataServicesPort|The listening HTTP port for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] OData web services.

Valid range: 1 - 65535
Default: 7048
Dynamically Updatable: No| -|V3 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of concurrent OData V3 connections per tenant that the server instance can process. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|V3 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of outstanding OData V3 connectons per tenant. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|V4 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of OData V4 reqests per tenant that the server instance can actively process at the same time. Requests that exceed the limit will wait in the queue until a slot becomes available. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| -|V4 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of pending OData V4 requests per tenant, including requests that are being processed and those waiting to be processed. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V3 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of OData V3 requests per tenant that the server instance can process at the same time. Requests that exceed the limit will wait in the queue until a time slot becomes available. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V3 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of pending OData V3 requests per tenant, including requests being processed and waiting to be processed. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Concurrent Requests|ODataV4MaxConcurrentRequests|Specifies the maximum number of OData V4 requests per tenant that the server instance can actively process at the same time. Requests that exceed the limit will wait in the queue until a time slot becomes available. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| +|V4 Max Queued Requests|ODataV4MaxRequestQueueSize|Specifies the maximum number of pending OData V4 requests per tenant, including requests being processed and waiting to be processed. When the limit is exceeded, a 429 (Too Many Requests) error occurs. If you don't want a limit, set the value `0`.

Default: 0
Dynamically Updatable: Yes| |Timeout|ODataServicesOperationTimeout |Specifies the maximum amount of time that the server instance can allocate to a single OData request. When the limit is exceeded, a 408 (Request Timeout) error occurs.

If you don't want a limit, set the value to `MaxValue`.

Time format: hh:mm:ss
Default: 00:08:00
Dynamically Updatable: Yes| > [!IMPORTANT] From 769fb65706e8f1c0f8910ae522e315871a6c4cf5 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 28 May 2020 15:44:12 +0200 Subject: [PATCH 014/950] Update devenv-directives-in-al.md --- dev-itpro/developer/devenv-directives-in-al.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dev-itpro/developer/devenv-directives-in-al.md b/dev-itpro/developer/devenv-directives-in-al.md index c63fcaa106..1ef31f8939 100644 --- a/dev-itpro/developer/devenv-directives-in-al.md +++ b/dev-itpro/developer/devenv-directives-in-al.md @@ -13,24 +13,26 @@ ms.author: solsen # Directives in AL -Anything can be made conditional, also table fields. Symbols can be defined in the manifest or in the beginning of a source file. There is currently no built-in symbols. +Anything can be made conditional, also table fields. Symbols can be defined in the manifest or in the beginning of a source file. There are currently no built-in symbols. -There will also be a server side check-in that create ParseOptions from manifest and it when parsing up syntax trees. + The following AL preprocessor directives are supported. For examples, see the [Examples](devenv-directives-in-al-md#Examples) section below. |Preprocessor directive |Description | |-----------------------|------------| -|#if | | +|#if | Specifies the start of an if clause. The #endif clause ends it. Compiles the code between the directives if the specified symbol is defined. | |#else | | |#elif | Combines `else` and `if`. If `#elif` is `true` the compiler evaluates all code between `#elif` and the next conditional directive.| |#endif | | -|#region | | -|#endregion | | |#define | | |#undef | | -|#pragma | | |#warning | | +|#error | | +|#line | | +|#region | | +|#endregion | | +|#pragma | | |#disable | | |#restore | | |#enable | | From 05fc056111dd700dbabc58bcbb8a941b22b97f9d Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Fri, 29 May 2020 10:01:10 +0200 Subject: [PATCH 015/950] Update devenv-directives-in-al.md --- dev-itpro/developer/devenv-directives-in-al.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-directives-in-al.md b/dev-itpro/developer/devenv-directives-in-al.md index 1ef31f8939..65c7ba7b2f 100644 --- a/dev-itpro/developer/devenv-directives-in-al.md +++ b/dev-itpro/developer/devenv-directives-in-al.md @@ -21,8 +21,8 @@ The following AL preprocessor directives are supported. For examples, see the [E |Preprocessor directive |Description | |-----------------------|------------| -|#if | Specifies the start of an if clause. The #endif clause ends it. Compiles the code between the directives if the specified symbol is defined. | -|#else | | +|#if | Specifies the start of a conditional clause. The #endif clause ends it. Compiles the code between the directives if the specified symbol is defined. | +|#else | Specifies a compound conditional clause. If none of the preceding clauses evaluates to `true`, the compiler will evaluate code between #else and #endif. | |#elif | Combines `else` and `if`. If `#elif` is `true` the compiler evaluates all code between `#elif` and the next conditional directive.| |#endif | | |#define | | From 722b2d3555669f35adc2873c6cc7d69a7991980f Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Fri, 29 May 2020 10:03:52 +0200 Subject: [PATCH 016/950] Update devenv-directives-in-al.md --- dev-itpro/developer/devenv-directives-in-al.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-itpro/developer/devenv-directives-in-al.md b/dev-itpro/developer/devenv-directives-in-al.md index 65c7ba7b2f..8894f53b2f 100644 --- a/dev-itpro/developer/devenv-directives-in-al.md +++ b/dev-itpro/developer/devenv-directives-in-al.md @@ -21,11 +21,11 @@ The following AL preprocessor directives are supported. For examples, see the [E |Preprocessor directive |Description | |-----------------------|------------| -|#if | Specifies the start of a conditional clause. The #endif clause ends it. Compiles the code between the directives if the specified symbol is defined. | +|#if | Specifies the start of a conditional clause. The `#endif` clause ends it. Compiles the code between the directives if the specified symbol is defined. | |#else | Specifies a compound conditional clause. If none of the preceding clauses evaluates to `true`, the compiler will evaluate code between #else and #endif. | |#elif | Combines `else` and `if`. If `#elif` is `true` the compiler evaluates all code between `#elif` and the next conditional directive.| -|#endif | | -|#define | | +|#endif | Specifies the end of a conditional clause that starts with `#if`. | +|#define | Used to define a symbol that can be used to specify conditions for a compilation. For example, `#define DEBUG`. | |#undef | | |#warning | | |#error | | From 218379d3f75193e77fa9437d4d3a95433e5a16cc Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Fri, 29 May 2020 10:16:05 +0200 Subject: [PATCH 017/950] Update devenv-directives-in-al.md --- dev-itpro/developer/devenv-directives-in-al.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dev-itpro/developer/devenv-directives-in-al.md b/dev-itpro/developer/devenv-directives-in-al.md index 8894f53b2f..ec726c05b9 100644 --- a/dev-itpro/developer/devenv-directives-in-al.md +++ b/dev-itpro/developer/devenv-directives-in-al.md @@ -26,11 +26,10 @@ The following AL preprocessor directives are supported. For examples, see the [E |#elif | Combines `else` and `if`. If `#elif` is `true` the compiler evaluates all code between `#elif` and the next conditional directive.| |#endif | Specifies the end of a conditional clause that starts with `#if`. | |#define | Used to define a symbol that can be used to specify conditions for a compilation. For example, `#define DEBUG`. | -|#undef | | -|#warning | | -|#error | | -|#line | | -|#region | | +|#undef | Used to undefine a symbol. | +|#warning | Specifies a compiler warning from code. | +|#error | Specifies a compiler error from code. | +|#region | Specifies a block of code that you can expand or collapse | |#endregion | | |#pragma | | |#disable | | From 4f593c258e416570b266c6c6f13f79efaaed2780 Mon Sep 17 00:00:00 2001 From: jswymer Date: Tue, 9 Jun 2020 08:15:52 +0200 Subject: [PATCH 018/950] Update configure-server-instance.md --- dev-itpro/administration/configure-server-instance.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 7f627bedb0..a92309f231 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -126,9 +126,10 @@ The following table describes fields on the **Database** tab in the [!INCLUDE[ad |Enable Trust of SQL Server Certificate|TrustSQLServerCertificate|Specifies whether [!INCLUDE[server](../developer/includes/server.md)] should trust the SQL Server certificate.

Default: Not enabled
Dynamically Updatable: No| |Search Timeout|SearchTimeout|Specifies the time (in seconds) that a search operation on lists in the client will continue until it's stopped. When the limit is reached, the following message displays in the client: **Searching for rows is taking too long. Try to search or filter using different criteria.**

Time format: hh:mm:ss
Default: 00:00:10
Dynamically Updatable: Yes| |SQL Bulk Import Batch Size|SqlBulkImportBatchSize|Specifies how many SQL memory chunks that a data import must be distributed across. Lowering the value increases the number of network transfers and decreases performance, but also lowers the amount of memory that the server instance consumes. If the database is on SQL Server 2016 or later, a low value can lead to large data files. If you don't want to use batching, specify 0.

Default: 448
Dynamically Updatable: No| -|SQL Command Timeout|SqlCommandTimeout|The contextual time-out for a SQL command.

Default: 0:30:00
Dynamically Updatable: No| +|SQL Command Timeout|SqlCommandTimeout|Specifies the contextual time-out for a SQL command.

Default: 0:30:00
Dynamically Updatable: No| |SQL Connection Idle Timeout|SqlConnectionIdleTimeout|Specifies the time that a SQL connection can remain idle before being closed. The value has the format HH:MM:SS.

Default: 00:05:00
Dynamically Updatable: Yes| -|SQL Connection Timeout|SqlConnectionTimeout|Specifies the time to wait while trying to connect to the database before stopping the attempt and generating an error. This setting also applies to begin, rollback, and commit of transactions.

The value has the format HH:MM:SS.

Default: 00:01:30
Dynamically Updatable: Yes| +|SQL Connection Timeout|SqlConnectionTimeout|Specifies the time to wait while trying to connect to the database before stopping the attempt and generating an error. This setting also applies to begin, rollback, and commit of transactions.

The value has the format HH:MM:SS.

Default: 00:01:30
Dynamically Updatable: Yes| +|SQL Management Command Timeout|SqlManagementCommandTimeout|Specifies the timeout for SQL commands related to management operations, for example schema synchronization and company management operations.

This setting enables you to set a different timeout for management operations than for other normal, day-to-day, runtime operations like a Record.FINDSET, which are controlled by the **Sql Command Timeout** setting.

When a negative value is specified for this setting, the **SQL Command Timeout** will be used. The value has the format HH:MM:SS.

Default: -1
Dynamically Updatable: Yes| |Enable SQL Parameters by Ordinal|SqlParametersByOrdinal|Specifies whether parameters in SQL statements are referenced by their ordinal number.

Enabling this setting improves performance when using buffered inserts.

Default: Enabled
Dynamically Updatable: No| |SQL Query Logging Threshold|SqlLongRunningThreshold|Specifies the amount of time (in milliseconds) that an SQL query can run before a warning event is recorded in the application log for the server instance. If this threshold is exceeded, the following event is logged: Action completed successfully, but it took longer than the given threshold.

Default: 1000
Dynamically Updatable: Yes| From 89b697a217a37c716e9c05a06cffc7bba74ad6bf Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 10 Jun 2020 12:33:19 +0200 Subject: [PATCH 019/950] Update devenv-testing-application.md --- dev-itpro/developer/devenv-testing-application.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dev-itpro/developer/devenv-testing-application.md b/dev-itpro/developer/devenv-testing-application.md index 71b65edfa6..bf89c8124f 100644 --- a/dev-itpro/developer/devenv-testing-application.md +++ b/dev-itpro/developer/devenv-testing-application.md @@ -83,6 +83,7 @@ if GETLASTERRORTEXT <> InvalidDateErrorMessage then ## Test with Permission Sets In most cases, users will be running with a permission set that limits their access to the functionality they need to do their work. To ensure that it works as intended, you can write application tests in AL that use specific permission sets when the test is run. For more information, see [Testing with Permission Sets](devenv-testing-with-permission-sets.md). + ## Testing Best Practices We recommend the following best practices for designing your application tests: @@ -113,7 +114,13 @@ We recommend the following best practices for designing your application tests: +## Enviroments Testing +The documentation topic should state something like this: +1. Production SaaS – running tests is not allowed. Running tests in production environment can cause damage to the business, since you may incidentally invoke external systems (e.g. CDS, PayPal, Webhook Subscriptions), slow down other users of your system or cause data corruption. +2. Sandbox – sandboxes can be used to run limited tests manually to verify functionality on SaaS Environment. Running large number of tests or tests that take long time (more than 15 minutes per test method) is not supported. +3. Docker / OnPrem– Docker or dedicated OnPrem Box should be the default environment for running large number of tests or setting up CI/CD gates. [We can add links here if we did this already on other topics] +For On-Prem installations you can disable the ability to run tests by setting TestAutomationEnabled to false in the server configuration. ## See Also From 0190e9eb325ca3418e8ae5c2a88545bb81dbfa9b Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 25 Jun 2020 11:31:21 +0200 Subject: [PATCH 020/950] Create devenv-maximumdatasetsize-property.md --- .../devenv-maximumdatasetsize-property.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md diff --git a/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md b/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md new file mode 100644 index 0000000000..b20a91ef09 --- /dev/null +++ b/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md @@ -0,0 +1,31 @@ +--- +title: "MaximumDataSetSize Property" +ms.custom: na +ms.date: 06/25/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: SusanneWindfeldPedersen +--- + +# MaximumDataSetSize Property +Sets the maximum amount of rows to be included on the report. + +## Applies To + +- Word report layouts. + +## Property Value + +## Syntax +``` + +``` + +## Remarks + +## See Also + +[Properties](devenv-properties.md) \ No newline at end of file From 353e86aa09e554645ffcb57a3b4de29d243ab5ad Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 25 Jun 2020 11:33:47 +0200 Subject: [PATCH 021/950] new --- .../devenv-maximumdatasetsize-property.md | 2 +- .../devenv-maximumdocumentcount-property.md | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md diff --git a/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md b/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md index b20a91ef09..5c2846bbd8 100644 --- a/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md +++ b/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md @@ -15,7 +15,7 @@ Sets the maximum amount of rows to be included on the report. ## Applies To -- Word report layouts. +- Reports ## Property Value diff --git a/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md b/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md new file mode 100644 index 0000000000..ff153b59d5 --- /dev/null +++ b/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md @@ -0,0 +1,31 @@ +--- +title: "MaximumDocumentCount Property" +ms.custom: na +ms.date: 06/25/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: SusanneWindfeldPedersen +--- + +# MaximumDocumentCount Property +Sets the maximum document count when generating a generating a Word layout report. + +## Applies To + +- Word reports + +## Property Value + +## Syntax +``` + +``` + +## Remarks + +## See Also + +[Properties](devenv-properties.md) \ No newline at end of file From 04e89b561c2164bc7aad39dad5b99a3a0f71f1d8 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 25 Jun 2020 11:35:18 +0200 Subject: [PATCH 022/950] Create devenv-executiontimeout-property.md --- .../devenv-executiontimeout-property.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 dev-itpro/developer/properties/devenv-executiontimeout-property.md diff --git a/dev-itpro/developer/properties/devenv-executiontimeout-property.md b/dev-itpro/developer/properties/devenv-executiontimeout-property.md new file mode 100644 index 0000000000..45f869b1db --- /dev/null +++ b/dev-itpro/developer/properties/devenv-executiontimeout-property.md @@ -0,0 +1,32 @@ +--- +title: "ExecutionTimeout Property" +ms.custom: na +ms.date: 06/25/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: SusanneWindfeldPedersen +--- + +# ExecutionTimeout Property + +Sets the maximum time the report will run after which it is automatically terminated. + +## Applies To + +- Word reports + +## Property Value + +## Syntax +``` + +``` + +## Remarks + +## See Also + +[Properties](devenv-properties.md) \ No newline at end of file From f65eb53a3c5dba3bff66c1d9ef966acd029f882d Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 25 Jun 2020 11:36:33 +0200 Subject: [PATCH 023/950] Create devenv-usercancelrequesthandling-property.md --- ...venv-usercancelrequesthandling-property.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md diff --git a/dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md b/dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md new file mode 100644 index 0000000000..6100245cac --- /dev/null +++ b/dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md @@ -0,0 +1,32 @@ +--- +title: "UserCancelRequestHandling Property" +ms.custom: na +ms.date: 06/25/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: SusanneWindfeldPedersen +--- + +# UserCancelRequestHandling Property + +Sets the behavior exhibited when the user attempts to cancel a running report. + +## Applies To + +- Word reports + +## Property Value + +## Syntax +``` + +``` + +## Remarks + +## See Also + +[Properties](devenv-properties.md) \ No newline at end of file From a5e3ef295faf6a05ba8fd0b51c665640bfbfd5e9 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 25 Jun 2020 11:38:16 +0200 Subject: [PATCH 024/950] Update devenv-executiontimeout-property.md --- .../developer/properties/devenv-executiontimeout-property.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/properties/devenv-executiontimeout-property.md b/dev-itpro/developer/properties/devenv-executiontimeout-property.md index 45f869b1db..5b723a4a21 100644 --- a/dev-itpro/developer/properties/devenv-executiontimeout-property.md +++ b/dev-itpro/developer/properties/devenv-executiontimeout-property.md @@ -12,7 +12,7 @@ author: SusanneWindfeldPedersen # ExecutionTimeout Property -Sets the maximum time the report will run after which it is automatically terminated. +Sets the maximum time the report will run after which it is automatically terminated. The format must be a timeout duration specified as `hh:mm:ss`. ## Applies To @@ -22,7 +22,7 @@ Sets the maximum time the report will run after which it is automatically termin ## Syntax ``` - +ExecutionTimeout := `10:05:55`; ``` ## Remarks From 139279d65896c539e1b50f02231f38a8e5359cce Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 25 Jun 2020 11:40:13 +0200 Subject: [PATCH 025/950] Update devenv-usercancelrequesthandling-property.md --- .../properties/devenv-usercancelrequesthandling-property.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md b/dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md index 6100245cac..36b51553c7 100644 --- a/dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md +++ b/dev-itpro/developer/properties/devenv-usercancelrequesthandling-property.md @@ -12,17 +12,17 @@ author: SusanneWindfeldPedersen # UserCancelRequestHandling Property -Sets the behavior exhibited when the user attempts to cancel a running report. +Sets the behavior exhibited when the user attempts to cancel a running report. The following values are permitted: `CancellationSafe`, `CancellationUnsafe`, and `CancellationSafeAndResumable`. ## Applies To -- Word reports +- Reports ## Property Value ## Syntax ``` - +UserCancelRequestHandling := CancellationSafe; ``` ## Remarks From eb7da88358d6c06846afbb3ac93fb534b6db5a37 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 25 Jun 2020 12:03:45 +0200 Subject: [PATCH 026/950] edit --- .../developer/properties/devenv-executiontimeout-property.md | 2 +- .../developer/properties/devenv-maximumdatasetsize-property.md | 3 ++- .../properties/devenv-maximumdocumentcount-property.md | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/properties/devenv-executiontimeout-property.md b/dev-itpro/developer/properties/devenv-executiontimeout-property.md index 5b723a4a21..2dc3e4d462 100644 --- a/dev-itpro/developer/properties/devenv-executiontimeout-property.md +++ b/dev-itpro/developer/properties/devenv-executiontimeout-property.md @@ -16,7 +16,7 @@ Sets the maximum time the report will run after which it is automatically termin ## Applies To -- Word reports +- Reports ## Property Value diff --git a/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md b/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md index 5c2846bbd8..081a30c65b 100644 --- a/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md +++ b/dev-itpro/developer/properties/devenv-maximumdatasetsize-property.md @@ -11,13 +11,14 @@ author: SusanneWindfeldPedersen --- # MaximumDataSetSize Property + Sets the maximum amount of rows to be included on the report. ## Applies To - Reports -## Property Value +## Property Value ## Syntax ``` diff --git a/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md b/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md index ff153b59d5..258c83acde 100644 --- a/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md +++ b/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md @@ -11,6 +11,7 @@ author: SusanneWindfeldPedersen --- # MaximumDocumentCount Property + Sets the maximum document count when generating a generating a Word layout report. ## Applies To From ce1c6135cf75f7b777ce2666a5f33bec693a9427 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Fri, 26 Jun 2020 12:21:56 +0200 Subject: [PATCH 027/950] Update devenv-maximumdocumentcount-property.md --- .../properties/devenv-maximumdocumentcount-property.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md b/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md index 258c83acde..d525128bde 100644 --- a/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md +++ b/dev-itpro/developer/properties/devenv-maximumdocumentcount-property.md @@ -12,11 +12,11 @@ author: SusanneWindfeldPedersen # MaximumDocumentCount Property -Sets the maximum document count when generating a generating a Word layout report. +Sets the maximum document count when generating a report by using `WordMergerDataItem`. ## Applies To -- Word reports +- Reports ## Property Value From 1844f2ee57b64d0ef75b08924683b03b13704ff0 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 26 Jun 2020 15:52:22 +0200 Subject: [PATCH 028/950] Update tenant-admin-center-environments.md --- .../tenant-admin-center-environments.md | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/dev-itpro/administration/tenant-admin-center-environments.md b/dev-itpro/administration/tenant-admin-center-environments.md index 67bb70e823..b8436c13b0 100644 --- a/dev-itpro/administration/tenant-admin-center-environments.md +++ b/dev-itpro/administration/tenant-admin-center-environments.md @@ -102,6 +102,92 @@ Canceling a session is sometimes the only way to unblock a customer. For example To cancel a session, select it from the list and then select **Cancel selected sessions**. +## Renaming an environment + +You can rename an environment by opening the environment card and clicking on the Rename button. + +In the Rename environment dialogue enter a new name to be used by this environment and click on Rename button. + +Confirm your intent to rename the environment. + +> [!IMPORTANT] +> It is important you study ## Environment rename considerations to understand the consequences before you confirm your intent to rename. Additionally, this operation requires a restart to the environment. We recommend doing this when no users are active in Business Central. + +The environment state will change to Preparing and back to Active again, once the rename has been completed. The new name will be available immediately. The environment will no longer be accessible using the old environment name. + +You can also review the log of Rename operation on the Operations page afterwards. + +## Environment rename considerations + +Environment name is a part of the environment URL, which uniquely identifies this environment among your other environments. Changing the name can affect many scenarios and integrations. While renaming an environment during early stages of a customer implementation may be a low risk operation, renaming an environment which has been used by customers for a longer period of time and is integrated with many external services and components is very risky and you must carefully plan for it. + +Here are some of the areas, which use the environment name, which you need to consider before attempting to rename an environment: + +- Web Services URL + +- External integrations which use Odata or SOAP + +- 3rd Party apps (AppSource / Per tenant extensions ) + +- Web Client URL + +- Bookmarked links to Web client + +- User-created links + + - Links to records/filters/pages/reports/tables/Profiles/Companies on each user's browser(s) and device(s). Thru regular usage, these links inevitably get saved across repositories such as Emails, Teams channels, Word docs, Excels, OneNote, Calendars, exchanged amongst users in same company, across companies, across environments, across tenants. Links can also be in desktop shortcuts eg. "launch POS". + + > [!NOTE] + > Admins do not have access to some/most of the above and therefore cannot update EnvName in behalf of the user. + + - Links in the notification mails sent from BC before name change won't find the correct environment after the change. + +- Partners, Partner Support, Customer Admins, Customer IT Support can also embed web client links in documentation, support websites, instructional steps and videos, and other material. Only some of this can be updated by an admin. + +- Browser cache. We store the Url including environment name in some of our cached data. This is cached browser-side, that is, in the user's browser(s) across device(s). Admins typically don't have access or control this. When a user loses their cache, they lose micro-personalizations to all their pages, preferences to + +- Integrations which embed the Web client - e.g. SharePoint apps composed of BC pages + +- Integrations which launch the Web client + +- Partner-developed mobile apps, web applications, etc. These likely originate from partners outside the customer's organization where the admin cannot update Urls. + +- Mobile apps incl. Windows 10 store app for desktop/tablet + + Affected only when users modify protocol handler before rename - to force the app to connect to environment with name different than "production". So if the user keeps working with "production" on mobile (which is default now), and the admin is renaming "prod2" to "myprod" the mobile user is not affected. Otherwise the app would throw an error and the user would have to bail out using a newly created protocol handler link. + +- Effect on the Business Central add-ins and integrations with other Microsoft services + + - Outlook Add-in + + The AddIn manifest saved into Exchange Server per org or per user includes the environment name. + + - Excel Add-in + + Each user's Excel sheet stores the Environment name. these Excels could be stored on user's desktop PCs, mobile devices, file shares, SharePointa, archives, etc. some of which will be unreachable by an admin to update. + + - Power BI + + All reports built (including the default ones we deploy from Role Center) or any Power BI apps installed before rename would be affected with no automatic way to repair. Partner/user would have to manually update the connections. + + - Power Apps/Automate + + All apps/flows built before rename would be affected with no automatic way to repair. Partner/user would have to manually update the connections. + + - CDS + + CDS Virtual Entity setup will store Environment name + + - Accountant Hub + +- Development scenarios + + - Publish to SB from VS Code. Launch.json configurations contain the sandbox name if different from "default", so these will be impacted and require source code updates + + - CI/CD pipelines for test and deploy, these could be impacted by environment renames + +- Azure AppInsights logs and metrics + ## See also [Working with Administration Tools](administration.md) From bddf75136a9095cf5b12696de88022f1cf60e032 Mon Sep 17 00:00:00 2001 From: Mike Borg Cardona Date: Fri, 26 Jun 2020 15:59:53 +0200 Subject: [PATCH 029/950] Update performance-users.md Minor updates: - use term "load" to indicate that FactBoxes are not processed - IE mode is no longer a pilot - generalized text so that it is not perceived as Edge gaining traction solely due to support for Windows Server --- dev-itpro/performance/performance-users.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dev-itpro/performance/performance-users.md b/dev-itpro/performance/performance-users.md index 005f65fabd..62b8c04ff9 100644 --- a/dev-itpro/performance/performance-users.md +++ b/dev-itpro/performance/performance-users.md @@ -20,9 +20,9 @@ This section describes how you can work with end-users to improve the performanc [!INCLUDE[prodshort](../developer/includes/prodshort.md)] supports multiple browsers that each offer a variety of features and capabilities. The browser plays a significant role in the responsiveness and fluidity of the user interface. See the list of supported, recommended browsers for [Business Central online](https://go.microsoft.com/fwlink/?linkid=2110804) and browsers for [Business Central on-premises](https://go.microsoft.com/fwlink/?linkid=2110719). -- Where possible, avoid older browsers such as Internet Explorer, and switch to one of our recommended modern browsers, such as the [new Microsoft Edge](https://www.microsoft.com/edge/). +- Where possible, avoid older browsers such as Internet Explorer or Edge Legacy, and switch to one of our recommended modern browsers, such as the [new Microsoft Edge](https://www.microsoft.com/edge/). The new Microsoft Edge can be installed to most versions of Windows including Windows Server. - Internet Explorer is still supported, but since the new Edge browser is available for Windows Server now, we see a declining rate of usage for Internet Explorer. You can also get [a pilot of Edge in IE mode](https://www.microsoft.com/edge/business). For more information, see [Microsoft Edge documentation](/deployedge/edge-ie-mode). + If other legacy applications require you to remain on Internet Explorer, consider using [Edge in Internet Explorer mode](https://www.microsoft.com/edge/business). For more information, see [Microsoft Edge documentation](/deployedge/edge-ie-mode). - Keep your browser always updated to the latest version. ## Choosing a network connection @@ -43,12 +43,9 @@ In order to provide an optimal experience, Business Central saves some preferenc - The overall structure of a page (but not business data) is cached on the client device after a page is accessed the first time. The time taken to load any page is also affected by the number of controls on the page. Users can improve performance on complex pages using these methods: -- By *collapsing* secondary content that may be needed only occasionally. For example, when the FactBox pane on a page is collapsed, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] saves time from attempting to display all the related facts. +- By *collapsing* secondary content that may be needed only occasionally. For example, when the FactBox pane on a page is collapsed, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] saves time from attempting to load and display all the related facts. - By *hiding* secondary content entirely from the page. For example, hiding Role Center parts or columns that are not used by the user, department or organization will also improve the time needed to load the page. Learn more about [Personalizing Your Workspace](/dynamics365/business-central/ui-personalization-user). -> [!NOTE] -> These suggestions only affect the time taken to display the content. All data and operations related to this content are still processed. - ## Agility of navigating and entering data Raw speed is not the only factor that determines whether users have a pleasant and performant experience. [!INCLUDE[prodshort](../developer/includes/prodshort.md)] provides numerous features that increase efficiency when exploring, navigating and entering data: From c5310de9780b916c77f20cf41bce887950262071 Mon Sep 17 00:00:00 2001 From: Mike Borg Cardona Date: Fri, 26 Jun 2020 17:12:22 +0200 Subject: [PATCH 030/950] Update devenv-adding-a-factbox-to-page.md Swapped mention of ListPlus so that we group entity pages together --- .../devenv-adding-a-factbox-to-page.md | 51 +++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md index 7e05504d37..8a932ae807 100644 --- a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md +++ b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md @@ -1,9 +1,9 @@ --- title: "Adding a FactBox to a Page" -description: A FactBox is located on the right-most side of a page. This area is used to display content including other pages, charts, and system parts such as Microsoft Outlook, Notes, and Record Links. +description: A FactBox is located on the right-most side of a page. This area is used to display related facts about the current record including charts, data from related tables, Notes, and Links. author: SusanneWindfeldPedersen ms.custom: na -ms.date: 04/01/2020 +ms.date: 06/26/2020 ms.reviewer: na ms.suite: na ms.tgt_pltfrm: na @@ -32,9 +32,9 @@ You define the FactBox by adding a FactBox area container control to the page. T - Document -- List - - ListPlus + +- List - Navigate @@ -127,6 +127,49 @@ page 50101 "Simple Customerlist Page" } ``` +## Performance considerations +Having a page composed of multiple FactBox pages that each process data from different sources can degrade performance. To mitigate this and improve the time it takes to load the page, Business Central version 17.0 and later optimizes the sequence in which content is loaded. The sequence is as follows: +1. Content on the hosting page is loaded first and users can immediately begin interacting with it. +2. The FactBox pane is loaded next where each FactBox is loaded independently in sequence starting from the top. + 1. FactBoxes having the Visible property evaluate to False will not be loaded. + 2. FactBoxes that are not within view are only loaded when the user scrolls them into view. +If the FactBox pane is collapsed, no FactBoxes are loaded until the user expands the FactBox pane. + +Below are some practical tips to help you make the most out of this optimization: + - Consider hiding any FactBoxes that represent secondary content which only some users will require. Learn more about [Choosing the Visibility of Parts](devenv-designing-parts#choosing-the-visibility-of-parts) + - Consider processing in the background for FactBoxes that require heavy processing. Learn more about [Using Page Background Tasks](devenv-designing-parts#using-page-background-tasks) + - Avoid having triggers on the hosting page that call into a FactBox as this forces the FactBox to ignore performance optimizations and load along with the content of the hosting page, adding to the total loading time. + +### FAQ about performance + +##### Are any FactBox triggers executed when the FactBox is hidden? +No. The trigger is only run once the FactBox is visible and within the user's view. + +##### How often are triggers executed if the FactBox pane is expanded, collapsed and then expanded again? +In this scenario, the OnOpenPage trigger is only run the first time. Once a FactBox is loaded, it is not loaded again for as long as the page remains open. + +##### Are FactBoxes processed asynchronously? +No. This optimization is simply a controlled sequence in which triggers are executed, still within the same session as the hosting page. For more information about asynchronous processing in the background, see [Designing page parts for page background tasks](devenv-page-background-tasks#partpages). + +##### Does this work with SubPageLink or SubPageView properties? +The use of these properties has no effect on the sequence of loading content on a page. Using properties such as SubPageView is preferred to writing trigger code to update a FactBox. + +##### Does this optimization apply to parts that are not FactBoxes? +This optimization does not apply to Role Center pages. When parts are used in the content area of a page, such as on a Card page, they are not loaded if their Visible property evaluates to False. + +##### Can I force a FactBox to load along with page content? +There is no AL API to force FactBoxes to load along with the content of the hosting page. + +##### Can i set the FactBox pane to start collapsed on all pages? +No. The default state of the FactBox pane is set by the Business Central platform and modifed by the user. + +##### Does the experience vary on different browsers? +Each browser has its own definition of whether a FactBox is considered within view or not. For example, opening Business Central in a new browser tab and quickly switching back to the original tab may pause loading of any FactBoxes in the new tab. + +##### Does this optimization apply to other form factors? +This applies to desktop, tablet and phone clients. + + ## See Also [Pages Overview](devenv-pages-overview.md) From 601d585328c1f2d95f7ac2ebc6f0fe437452294d Mon Sep 17 00:00:00 2001 From: Mike Borg Cardona Date: Fri, 26 Jun 2020 17:13:42 +0200 Subject: [PATCH 031/950] Update devenv-designing-parts.md --- dev-itpro/developer/devenv-designing-parts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/developer/devenv-designing-parts.md b/dev-itpro/developer/devenv-designing-parts.md index 78353b5e93..b4de21c913 100644 --- a/dev-itpro/developer/devenv-designing-parts.md +++ b/dev-itpro/developer/devenv-designing-parts.md @@ -75,7 +75,7 @@ When you design a page with hidden parts, users can choose to display those part > [!NOTE] > Parts embedded on Role Center pages can't be made visible using expressions, because the hosting Role Center page can't execute code. -## Using page background tasks +### Using page background tasks Like other page types, you can design a part page to use one or more page background tasks. However, unlike other page types, a part page won't display any data until all page background tasks have completed. For more information about this behavior, see [Designing part pages for page background tasks](devenv-page-background-tasks.md#partpages). From f94d0eb7e53be12db3ad36bde5ca4061922a610a Mon Sep 17 00:00:00 2001 From: Mike Borg Cardona Date: Fri, 26 Jun 2020 17:19:47 +0200 Subject: [PATCH 032/950] Update devenv-adding-a-factbox-to-page.md --- dev-itpro/developer/devenv-adding-a-factbox-to-page.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md index 8a932ae807..01eadcd7f0 100644 --- a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md +++ b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md @@ -128,7 +128,7 @@ page 50101 "Simple Customerlist Page" ``` ## Performance considerations -Having a page composed of multiple FactBox pages that each process data from different sources can degrade performance. To mitigate this and improve the time it takes to load the page, Business Central version 17.0 and later optimizes the sequence in which content is loaded. The sequence is as follows: +Having a page composed of multiple FactBox pages that each process data from different sources can degrade performance. To improve responsiveness and the time it takes to load the page, Business Central version 17.0 and later optimizes the sequence in which content is loaded. The sequence is as follows: 1. Content on the hosting page is loaded first and users can immediately begin interacting with it. 2. The FactBox pane is loaded next where each FactBox is loaded independently in sequence starting from the top. 1. FactBoxes having the Visible property evaluate to False will not be loaded. From ad9b4cd2ce7ac07acfd68f6edce347cb18533003 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Mon, 29 Jun 2020 10:28:03 +0200 Subject: [PATCH 033/950] edits --- .../devenv-adding-a-factbox-to-page.md | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md index 01eadcd7f0..176fb2bd76 100644 --- a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md +++ b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md @@ -128,16 +128,18 @@ page 50101 "Simple Customerlist Page" ``` ## Performance considerations -Having a page composed of multiple FactBox pages that each process data from different sources can degrade performance. To improve responsiveness and the time it takes to load the page, Business Central version 17.0 and later optimizes the sequence in which content is loaded. The sequence is as follows: + +Having a page composed of multiple FactBox pages that each process data from different sources can degrade performance. To improve responsiveness and the time it takes to load the page, [!INCLUDE[prodshort](includes/prodshort.md)] 2020 release wave 2 and later optimizes the sequence in which content is loaded. The sequence is as follows: + 1. Content on the hosting page is loaded first and users can immediately begin interacting with it. 2. The FactBox pane is loaded next where each FactBox is loaded independently in sequence starting from the top. - 1. FactBoxes having the Visible property evaluate to False will not be loaded. + 1. FactBoxes having the `Visible` property evaluate to `false` will not be loaded. 2. FactBoxes that are not within view are only loaded when the user scrolls them into view. If the FactBox pane is collapsed, no FactBoxes are loaded until the user expands the FactBox pane. Below are some practical tips to help you make the most out of this optimization: - - Consider hiding any FactBoxes that represent secondary content which only some users will require. Learn more about [Choosing the Visibility of Parts](devenv-designing-parts#choosing-the-visibility-of-parts) - - Consider processing in the background for FactBoxes that require heavy processing. Learn more about [Using Page Background Tasks](devenv-designing-parts#using-page-background-tasks) + - Consider hiding any FactBoxes that represent secondary content which only some users will require. Learn more about [Choosing the Visibility of Parts](devenv-designing-parts#choosing-the-visibility-of-parts). + - Consider processing in the background for FactBoxes that require heavy processing. Learn more about [Using Page Background Tasks](devenv-designing-parts#using-page-background-tasks). - Avoid having triggers on the hosting page that call into a FactBox as this forces the FactBox to ignore performance optimizations and load along with the content of the hosting page, adding to the total loading time. ### FAQ about performance @@ -146,28 +148,28 @@ Below are some practical tips to help you make the most out of this optimization No. The trigger is only run once the FactBox is visible and within the user's view. ##### How often are triggers executed if the FactBox pane is expanded, collapsed and then expanded again? -In this scenario, the OnOpenPage trigger is only run the first time. Once a FactBox is loaded, it is not loaded again for as long as the page remains open. +In this scenario, the `OnOpenPage` trigger is only run the first time. Once a FactBox is loaded, it is not loaded again for as long as the page remains open. ##### Are FactBoxes processed asynchronously? No. This optimization is simply a controlled sequence in which triggers are executed, still within the same session as the hosting page. For more information about asynchronous processing in the background, see [Designing page parts for page background tasks](devenv-page-background-tasks#partpages). ##### Does this work with SubPageLink or SubPageView properties? -The use of these properties has no effect on the sequence of loading content on a page. Using properties such as SubPageView is preferred to writing trigger code to update a FactBox. +The use of these properties has no effect on the sequence of loading content on a page. Using properties such as `SubPageView` is preferred to writing trigger code to update a FactBox. ##### Does this optimization apply to parts that are not FactBoxes? -This optimization does not apply to Role Center pages. When parts are used in the content area of a page, such as on a Card page, they are not loaded if their Visible property evaluates to False. +This optimization does not apply to Role Center pages. When parts are used in the content area of a page, such as on a Card page, they are not loaded if their `Visible` property evaluates to `false`. ##### Can I force a FactBox to load along with page content? There is no AL API to force FactBoxes to load along with the content of the hosting page. ##### Can i set the FactBox pane to start collapsed on all pages? -No. The default state of the FactBox pane is set by the Business Central platform and modifed by the user. +No. The default state of the FactBox pane is set by the [!INCLUDE[prodshort](includes/prodshort.md)] platform and modifed by the user. ##### Does the experience vary on different browsers? -Each browser has its own definition of whether a FactBox is considered within view or not. For example, opening Business Central in a new browser tab and quickly switching back to the original tab may pause loading of any FactBoxes in the new tab. +Each browser has its own definition of whether a FactBox is considered within view or not. For example, opening [!INCLUDE[prodshort](includes/prodshort.md)] in a new browser tab and quickly switching back to the original tab may pause loading of any FactBoxes in the new tab. ##### Does this optimization apply to other form factors? -This applies to desktop, tablet and phone clients. +This applies to desktop, tablet, and phone clients. ## See Also From 5b0b2605aaa2570e5fdb1abe8a3066e343a4b8a0 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Mon, 29 Jun 2020 10:29:04 +0200 Subject: [PATCH 034/950] Update devenv-adding-a-factbox-to-page.md --- .../devenv-adding-a-factbox-to-page.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md index 176fb2bd76..85865ac30b 100644 --- a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md +++ b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md @@ -144,34 +144,33 @@ Below are some practical tips to help you make the most out of this optimization ### FAQ about performance -##### Are any FactBox triggers executed when the FactBox is hidden? +#### Are any FactBox triggers executed when the FactBox is hidden? No. The trigger is only run once the FactBox is visible and within the user's view. -##### How often are triggers executed if the FactBox pane is expanded, collapsed and then expanded again? +#### How often are triggers executed if the FactBox pane is expanded, collapsed and then expanded again? In this scenario, the `OnOpenPage` trigger is only run the first time. Once a FactBox is loaded, it is not loaded again for as long as the page remains open. -##### Are FactBoxes processed asynchronously? +#### Are FactBoxes processed asynchronously? No. This optimization is simply a controlled sequence in which triggers are executed, still within the same session as the hosting page. For more information about asynchronous processing in the background, see [Designing page parts for page background tasks](devenv-page-background-tasks#partpages). -##### Does this work with SubPageLink or SubPageView properties? +#### Does this work with SubPageLink or SubPageView properties? The use of these properties has no effect on the sequence of loading content on a page. Using properties such as `SubPageView` is preferred to writing trigger code to update a FactBox. -##### Does this optimization apply to parts that are not FactBoxes? +#### Does this optimization apply to parts that are not FactBoxes? This optimization does not apply to Role Center pages. When parts are used in the content area of a page, such as on a Card page, they are not loaded if their `Visible` property evaluates to `false`. -##### Can I force a FactBox to load along with page content? +#### Can I force a FactBox to load along with page content? There is no AL API to force FactBoxes to load along with the content of the hosting page. -##### Can i set the FactBox pane to start collapsed on all pages? +#### Can i set the FactBox pane to start collapsed on all pages? No. The default state of the FactBox pane is set by the [!INCLUDE[prodshort](includes/prodshort.md)] platform and modifed by the user. -##### Does the experience vary on different browsers? +#### Does the experience vary on different browsers? Each browser has its own definition of whether a FactBox is considered within view or not. For example, opening [!INCLUDE[prodshort](includes/prodshort.md)] in a new browser tab and quickly switching back to the original tab may pause loading of any FactBoxes in the new tab. -##### Does this optimization apply to other form factors? +#### Does this optimization apply to other form factors? This applies to desktop, tablet, and phone clients. - ## See Also [Pages Overview](devenv-pages-overview.md) From d471c413a11dcf993ba1f55b5038f039f1ec2658 Mon Sep 17 00:00:00 2001 From: jswymer Date: Tue, 30 Jun 2020 12:59:14 +0200 Subject: [PATCH 035/950] Update tenant-admin-center-environments.md --- .../administration/tenant-admin-center-environments.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev-itpro/administration/tenant-admin-center-environments.md b/dev-itpro/administration/tenant-admin-center-environments.md index b8436c13b0..d77a569ae6 100644 --- a/dev-itpro/administration/tenant-admin-center-environments.md +++ b/dev-itpro/administration/tenant-admin-center-environments.md @@ -102,7 +102,10 @@ Canceling a session is sometimes the only way to unblock a customer. For example To cancel a session, select it from the list and then select **Cancel selected sessions**. -## Renaming an environment +## Renaming an environment + +> [!NOTE] +> This feature is in preview. It might change or be removed in the future updates. You can rename an environment by opening the environment card and clicking on the Rename button. @@ -117,7 +120,7 @@ The environment state will change to Preparing and back to Active again, once th You can also review the log of Rename operation on the Operations page afterwards. -## Environment rename considerations +## Environment rename considerations Environment name is a part of the environment URL, which uniquely identifies this environment among your other environments. Changing the name can affect many scenarios and integrations. While renaming an environment during early stages of a customer implementation may be a low risk operation, renaming an environment which has been used by customers for a longer period of time and is integrated with many external services and components is very risky and you must carefully plan for it. From 1cccc57737eb6b66956a3b322dc63137fc88178c Mon Sep 17 00:00:00 2001 From: jswymer Date: Tue, 30 Jun 2020 15:56:48 +0200 Subject: [PATCH 036/950] Create azure-key-vault.md --- dev-itpro/administration/azure-key-vault.md | 385 ++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 dev-itpro/administration/azure-key-vault.md diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/azure-key-vault.md new file mode 100644 index 0000000000..a1d716e588 --- /dev/null +++ b/dev-itpro/administration/azure-key-vault.md @@ -0,0 +1,385 @@ +--- +title: User Authentication with Azure AD for Single Sign-on +description: Associate an existing Microsoft account with user account to achieve single sign-on between the Web client and Office 365. +ms.custom: na +ms.date: 04/01/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: jswymer +--- +# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions + +Some [!INCLUDE[prodshort](../developer/includes/prodshort.md) extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md) services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. + +These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md) extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. + +The credential is a kind of secret. It is secret to the extension. It shouldn't leak to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. + +Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. + + +## Specifying Azure Key Vault in extensions + +To use an Azure Key Vault for an extension, you specify the key vault the extension's manifest file (app.json), like this: + +``` + + +    "keyVaultUrls": [ + +        "https://mykeyvault.vault.azure.net" + +    ] + +``` + +Then, you can add code to the extension to read secrets from the key vault at runtime, like this: + +``` +page 50100 HelloWorldPage + +{ + +    var + +        SecretProvider: Codeunit "App Key Vault Secret Provider"; + +        SecretValue: Text; + +    trigger OnOpenPage(); + +    begin + +        if SecretProvider.TryInitializeFromCurrentApp() then begin + +            SecretProvider.GetSecret('secret1', SecretValue); + +            Message('retrieved secret: ' + SecretValue); + +        end + +        else + +            Message('ERROR: ' + GetLastErrorText()); + +    end; + +} + +``` + +The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. + + +## Specifying two Azure Key Vaults + +An extension manifest can specify up to two Azure Key Vaults, like this: + +``` + +    "keyVaultUrls": [ + +        "https://myfirstkeyvault.vault.azure.net", + +        "https://mysecondkeyvault.vault.azure.net" + +    ] +``` + +The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. + +## Setting up Azure Key Vault for on-prem installations + +Follow these steps to configure a local installation to use the App Key Vault feature. + +### Prerequisite + +- Configure Azure Active Directory (Azure AD) authentication for authenticating [!INCLUDE[prodshort](../developer/includes/prodshort.md)] users. + + For more information, see [Authenticating Users with Azure Active Directory](authenticating-users-with-azure-active-directory.md). + +- Obtain a security certificate + + As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. + + + +There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. + +The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](/azure/key-vault/secrets/quick-create-portal). + +For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). + +### Register an application for reading from key vaults + +Next, register a new application on your Azure AD tenant for reading secrets from the key vaults. + +When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. + +There are a couple steps involved in this task. The steps in this task are done from the the [Azure portal](https://portal.azure.com).Certificates & secrets + + +1. Register an Azure AD application for the reading key vault. + + You add the new application by using the [Azure portal](https://portal.azure.com). For guidelines, see [Register your application with your Azure Active Directory tenant](/azure/active-directory/active-directory-app-registration). + + When you add an application to an Azure AD tenant, you must specify the following information: + + |Setting|Description| + |-------|-----------| + |Name|The name of your application as it will display to your users, such as *Business Central Key Vault Reader*.| + |Supported account types|Specifies which accounts that you would like your application to support. For purposes of this article, select **Accounts in this organizational directory only**. | + + + When completed, the **Overview** displays in the portal for the new application. + +2. Upload the security certificate to the registered application. + + In this step, you upload the certificate file that you obtained as part of the prerequisites. + + From the registered applications overview page, select **Certificates & secrets** > **Upload certificate**, and follow instructions. + + +In the Azure portal, create one or two Key Vaults in your Azure subscription. + +Add the secrets to the key vault(s), which you want to make available to your extension. + + + +Access the secrets in the key vaults from your extension + +Specify the key vaults in the extension manifest as illustrated above. + +Access the secrets in the AL code as illustrated above. + + + +If you execute the AL code at this point, it will fail to access the secrets, and the reason is that the key vaults haven't granted anybody permission to read secrets in the key vaults. This must be done using the Access Policies on the key vaults. Specifically, we must grant an AAD application permission to read secrets from the key vaults. + + + +Create an AAD application + +In the Azure portal, register a new AAD application by following these steps: + +Open the Azure Active Directory blade + +Click "App registrations" + +Click "New registration" + +Give a name such as "Business Central Key Vault Reader" + +Click "Register" +s +Make a note of the "Application (client) ID" guid. + +Click "Certificates & secrets" + +We need to add a certificate here - see next step + + + +Register a certificate on the AAD application + +Obtain a certificate as you normally obtain certificates. + + + +You can also generate a self-signed certificate, for example using the following commands: + +Generate a new self-signed certificate: + +$cert = New-SelfSignedCertificate -Subject "BusinessCentralKeyVaultReader" -Provider "Microsoft Strong Cryptographic Provider" + +The generated certificate will be placed in the LocalMachine\My certificate store. + +You can print the certificate's thumbprint (you will need it later) using this command: + +$cert.Thumbprint + +Next, export the certificate to a .cer file: + +Export-Certificate -Cert $cert -FilePath BusinessCentralKeyVaultReader.cer + + + +Go back to the Azure portal, locate the AAD application, and click on the "Certificates & secrets" page. Upload the .cer file. + + + +Grant the AAD application permission to read secrets from the key vaults + +In the Azure portal, locate the key vaults again, and perform the following steps for each of them: + +Click "Access policies" + +Click "Add Access Policy" + +Select "Secret permission": "Get" + +Click "Select principal" and search for the AAD application above, either using its application/client ID or using its name + +Click "Select" + +Click "Add" + +Click "Save" + + + +Configure the NST + +Finally, it's time to configure the NST to use the AAD application and its certificate when authenticating to the key vaults. This is done by setting the following values: + + + +AzureKeyVaultClientCertificateStoreLocation + +LocalMachine + +AzureKeyVaultClientCertificateStoreName + +My + +AzureKeyVaultClientCertificateThumbprint + + + +AzureKeyVaultClientId + + + +AzureKeyVaultAppSecretsPublisherValidationEnabled + +false + + + +Caution: Setting the AzureKeyVaultAppSecretsPublisherValidationEnabled to false means the NST will not perform any additional validation that the extension has the right to read secrets from the key vaults that it specified. This implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. + + + +At this point, you can run your extension and read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. + + + + + +Instructions for SaaS + +In Business Central SaaS, the App Key Vault feature is available for all App Source apps, however, there are onboarding steps. + + + +Note: Why isn't the App Key Vault feature available for PTEs (Per-Tenant Extensions) and developer extensions in SaaS? For security reasons. Since the Business Central SaaS service has permission to access key vaults from different ISVs, it needs a way to determine if a given extension has the right to access the key vaults that it specifies in the extension manifest. And since the Business Central SaaS service has no way of verifying who authored a given PTE or developer extension, it also cannot restrict access to only the author's key vaults. + + + +Some steps are the same as for on-premises installations. You need to create one or two key vaults, and you need to adjust your extension manifest and AL code to read from these key vaults. + + + +Grant a Business Central SaaS AAD application permission to read secrets from your key vaults + +When Business Central runs in SaaS, it is configured to use an AAD application that Microsoft manages, and this AAD application needs permission to read secrets from your key vaults. Perform these steps to grant it access: + +Install-Module AzureAD + +Import-Module AzureAD + +Connect-AzureAD + +New-Azureadserviceprincipal + +New-AzureADServicePrincipal -AppId 7e97dcfb-bcdd-426e-8f0a-96439602627a + +These step provision Microsoft's centralized AAD application into your AAD tenant, where it now "lives" together with your key vaults. + +The next step is to grant the AAD application permissions to your key vaults. + +Please follow the same steps as for on-premises installations, as described under "Grant the AAD application permission to read secrets from the key vaults". + + + +Contact Microsoft to enable the App Key Vault feature for your App Source app + +Please send an email to TODO@microsoft.com to start the onboarding process. This should be done before you publish your updated extension to Partner Center. + + + +The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. + + + + + +Security considerations + +Please keep the following in mind when you use the App Key Vault feature. + + + +Use NonDebuggable + +As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the functions as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. + + + +Don't pass the App Key Vault Secret Provider to untrusted code + +Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. + + + +Run with publisher validation + +In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. + + + +When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: + +Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId + +Only if this check is satisfied will the initialization succeed. + +How does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: + +Publish-NavApp … -PublisherAzureActiveDirectoryTenantId + +In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. + +## See Also + +[Authentication and Credential Types](Users-Credential-Types.md) +[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) \ No newline at end of file From 54fe66b5df45205d21726efd68fb623d28044fd7 Mon Sep 17 00:00:00 2001 From: jswymer Date: Tue, 30 Jun 2020 17:10:37 +0200 Subject: [PATCH 037/950] Update azure-key-vault.md --- dev-itpro/administration/azure-key-vault.md | 58 +++++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/azure-key-vault.md index a1d716e588..0151d9fee8 100644 --- a/dev-itpro/administration/azure-key-vault.md +++ b/dev-itpro/administration/azure-key-vault.md @@ -135,14 +135,13 @@ The easiest way is to use the Azure portal. For instructions, see [Quickstart: S For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). -### Register an application for reading from key vaults +### Register a key vault reader application in Azure AD Next, register a new application on your Azure AD tenant for reading secrets from the key vaults. When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. -There are a couple steps involved in this task. The steps in this task are done from the the [Azure portal](https://portal.azure.com).Certificates & secrets - +The steps in this task are done from the the [Azure portal](https://portal.azure.com). 1. Register an Azure AD application for the reading key vault. @@ -162,13 +161,64 @@ There are a couple steps involved in this task. The steps in this task are done --> When completed, the **Overview** displays in the portal for the new application. + Make a note of the **Display name** and/or **Application (client) ID**. You will use this information later. + 2. Upload the security certificate to the registered application. In this step, you upload the certificate file that you obtained as part of the prerequisites. - From the registered applications overview page, select **Certificates & secrets** > **Upload certificate**, and follow instructions. + From the registered applications overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions. + +### Grant the key vault reader application permission to read secrets from the key vaults + +In this task, you grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Open the key vault in the portal. +2. Select **Access policies**, then **Add Access Policy**. +3. Set **Secret Permissions** to **Get**. +4. Select **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. +5. Select **Add**, then **Save**. + +At this point, the work in Azure is finished. + +## Configure the Business Central Server + +Finally, it's time to configure the NST to use the AAD application and its certificate when authenticating to the key vaults. This is done by setting the following values: + + + +AzureKeyVaultClientCertificateStoreLocation + +LocalMachine + +AzureKeyVaultClientCertificateStoreName + +My + +AzureKeyVaultClientCertificateThumbprint + + + +AzureKeyVaultClientId + + + +AzureKeyVaultAppSecretsPublisherValidationEnabled + +false + + + +Caution: Setting the AzureKeyVaultAppSecretsPublisherValidationEnabled to false means the NST will not perform any additional validation that the extension has the right to read secrets from the key vaults that it specified. This implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. + + + +At this point, you can run your extension and read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. + + +## In the Azure portal, create one or two Key Vaults in your Azure subscription. Add the secrets to the key vault(s), which you want to make available to your extension. From d2303d29a5b620c3065f79aa914b901b2ddf7a27 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 1 Jul 2020 08:18:23 +0200 Subject: [PATCH 038/950] Update azure-key-vault.md --- dev-itpro/administration/azure-key-vault.md | 48 ++++++++------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/azure-key-vault.md index 0151d9fee8..75540be34c 100644 --- a/dev-itpro/administration/azure-key-vault.md +++ b/dev-itpro/administration/azure-key-vault.md @@ -93,9 +93,9 @@ The use case for specifying two key vaults is to ensure high availability. At ru ## Setting up Azure Key Vault for on-prem installations -Follow these steps to configure a local installation to use the App Key Vault feature. +Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. -### Prerequisite +### Prerequisites - Configure Azure Active Directory (Azure AD) authentication for authenticating [!INCLUDE[prodshort](../developer/includes/prodshort.md)] users. @@ -105,15 +105,16 @@ Follow these steps to configure a local installation to use the App Key Vault fe As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. - - Export-Certificate -Cert $cert -FilePath c:\certs\BusinessCentralKeyVaultReader.cer - ``` - > ### Create the Azure Key Vault with secrets @@ -173,7 +174,7 @@ The steps in this task are done from the the [Azure portal](https://portal.azure In this task, you grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). -1. Open the key vault in the portal. +1. Open the key vault in the portal. 2. Select **Access policies**, then **Add Access Policy**. 3. Set **Secret Permissions** to **Get**. 4. Select **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. @@ -185,27 +186,14 @@ At this point, the work in Azure is finished. Finally, it's time to configure the NST to use the AAD application and its certificate when authenticating to the key vaults. This is done by setting the following values: - - -AzureKeyVaultClientCertificateStoreLocation - -LocalMachine - -AzureKeyVaultClientCertificateStoreName - -My +|Setting|Value| +|-------|-----| +|AzureKeyVaultClientCertificateStoreLocation|LocalMachine| +|AzureKeyVaultClientCertificateStoreName|MY| +|AzureKeyVaultClientCertificateThumbprint|| +|AzureKeyVaultClientId|| +|AzureKeyVaultAppSecretsPublisherValidationEnabled|false| -AzureKeyVaultClientCertificateThumbprint - - - -AzureKeyVaultClientId - - - -AzureKeyVaultAppSecretsPublisherValidationEnabled - -false From 8b39c8608d8563afffc054a5d029ca962c6cb1ac Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 1 Jul 2020 09:27:01 +0200 Subject: [PATCH 039/950] Update azure-key-vault.md --- dev-itpro/administration/azure-key-vault.md | 196 ++++---------------- 1 file changed, 31 insertions(+), 165 deletions(-) diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/azure-key-vault.md index 75540be34c..6594042889 100644 --- a/dev-itpro/administration/azure-key-vault.md +++ b/dev-itpro/administration/azure-key-vault.md @@ -1,4 +1,4 @@ ---- +---""''©™®* title: User Authentication with Azure AD for Single Sign-on description: Associate an existing Microsoft account with user account to achieve single sign-on between the Web client and Office 365. ms.custom: na @@ -91,7 +91,7 @@ An extension manifest can specify up to two Azure Key Vaults, like this: The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. -## Setting up Azure Key Vault for on-prem installations +## Setting up Azure Key Vault for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. @@ -168,7 +168,7 @@ The steps in this task are done from the the [Azure portal](https://portal.azure In this step, you upload the certificate file that you obtained as part of the prerequisites. - From the registered applications overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions. + From the key vault reader application overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions to locate and upload the certificate. ### Grant the key vault reader application permission to read secrets from the key vaults @@ -184,164 +184,38 @@ At this point, the work in Azure is finished. ## Configure the Business Central Server -Finally, it's time to configure the NST to use the AAD application and its certificate when authenticating to the key vaults. This is done by setting the following values: - -|Setting|Value| -|-------|-----| -|AzureKeyVaultClientCertificateStoreLocation|LocalMachine| -|AzureKeyVaultClientCertificateStoreName|MY| -|AzureKeyVaultClientCertificateThumbprint|| -|AzureKeyVaultClientId|| -|AzureKeyVaultAppSecretsPublisherValidationEnabled|false| - - - - -Caution: Setting the AzureKeyVaultAppSecretsPublisherValidationEnabled to false means the NST will not perform any additional validation that the extension has the right to read secrets from the key vaults that it specified. This implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. - - - -At this point, you can run your extension and read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. - - - - -## -In the Azure portal, create one or two Key Vaults in your Azure subscription. - -Add the secrets to the key vault(s), which you want to make available to your extension. - - - -Access the secrets in the key vaults from your extension - -Specify the key vaults in the extension manifest as illustrated above. - -Access the secrets in the AL code as illustrated above. - - - -If you execute the AL code at this point, it will fail to access the secrets, and the reason is that the key vaults haven't granted anybody permission to read secrets in the key vaults. This must be done using the Access Policies on the key vaults. Specifically, we must grant an AAD application permission to read secrets from the key vaults. - - - -Create an AAD application - -In the Azure portal, register a new AAD application by following these steps: - -Open the Azure Active Directory blade - -Click "App registrations" - -Click "New registration" - -Give a name such as "Business Central Key Vault Reader" - -Click "Register" -s -Make a note of the "Application (client) ID" guid. - -Click "Certificates & secrets" - -We need to add a certificate here - see next step - - - -Register a certificate on the AAD application - -Obtain a certificate as you normally obtain certificates. - - - -You can also generate a self-signed certificate, for example using the following commands: - -Generate a new self-signed certificate: - -$cert = New-SelfSignedCertificate -Subject "BusinessCentralKeyVaultReader" -Provider "Microsoft Strong Cryptographic Provider" - -The generated certificate will be placed in the LocalMachine\My certificate store. - -You can print the certificate's thumbprint (you will need it later) using this command: - -$cert.Thumbprint +Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. -Next, export the certificate to a .cer file: +You can configure the server instance using any of the following methods: -Export-Certificate -Cert $cert -FilePath BusinessCentralKeyVaultReader.cer +- [!INCLUDE[admintool](../developer/includes/admintool.md)- +- [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration) of the [!INCLUDE[adminshell](../developer/includes/adminshell.md). +- Manually modifying the server instances CustomSetting.config file. - - -Go back to the Azure portal, locate the AAD application, and click on the "Certificates & secrets" page. Upload the .cer file. - - - -Grant the AAD application permission to read secrets from the key vaults - -In the Azure portal, locate the key vaults again, and perform the following steps for each of them: - -Click "Access policies" - -Click "Add Access Policy" - -Select "Secret permission": "Get" - -Click "Select principal" and search for the AAD application above, either using its application/client ID or using its name - -Click "Select" - -Click "Add" - -Click "Save" - - - -Configure the NST - -Finally, it's time to configure the NST to use the AAD application and its certificate when authenticating to the key vaults. This is done by setting the following values: +For more information about using these tools, see [Configuring Business Central Server](configure-server-instance.md). +### Required settings +The following table describes the settings that you configure to enable Azure key vault on the server instance: +|Setting|Key name in CustomSetting.config|Value|Example| +|--------|-------------------------------|-----|-------| +|Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Specifies the certificate store location for the Key Vault client certificate.|LocalMachine| +|Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Specifies the certificate store name for the Key Vault client certificate.|MY| +|Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint||649419e4fbb87340f5a0f995e605b74c5f6d943e| +|Client ID|AzureKeyVaultClientId|Specifies the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| +|AzureKeyVaultAppSecretsPublisherValidationEnabled|false| -AzureKeyVaultClientCertificateStoreLocation - -LocalMachine - -AzureKeyVaultClientCertificateStoreName - -My - -AzureKeyVaultClientCertificateThumbprint - - - -AzureKeyVaultClientId - - - -AzureKeyVaultAppSecretsPublisherValidationEnabled - -false - - -Caution: Setting the AzureKeyVaultAppSecretsPublisherValidationEnabled to false means the NST will not perform any additional validation that the extension has the right to read secrets from the key vaults that it specified. This implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. +> [!IMPORTANT] +> Setting the AzureKeyVaultAppSecretsPublisherValidationEnabled to false means the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. - +At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. At this point, you can run your extension and read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. - - - +## Setting up Azure Key Vault for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online -Instructions for SaaS - -In Business Central SaaS, the App Key Vault feature is available for all App Source apps, however, there are onboarding steps. - - - -Note: Why isn't the App Key Vault feature available for PTEs (Per-Tenant Extensions) and developer extensions in SaaS? For security reasons. Since the Business Central SaaS service has permission to access key vaults from different ISVs, it needs a way to determine if a given extension has the right to access the key vaults that it specifies in the extension manifest. And since the Business Central SaaS service has no way of verifying who authored a given PTE or developer extension, it also cannot restrict access to only the author's key vaults. - - +In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. Some steps are the same as for on-premises installations. You need to create one or two key vaults, and you need to adjust your extension manifest and AL code to read from these key vaults. @@ -381,37 +255,29 @@ The onboarding process involves a manual verification step that verifies that yo -Security considerations +## Security considerations -Please keep the following in mind when you use the App Key Vault feature. +Keep the following information in mind when you use the App Key Vault feature. - - -Use NonDebuggable +### Use NonDebuggable -As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the functions as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. +As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. - - -Don't pass the App Key Vault Secret Provider to untrusted code +### Don't pass the App Key Vault Secret Provider to untrusted code Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. - - -Run with publisher validation +### Run with publisher validation In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. - - When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: -Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId +`Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId` Only if this check is satisfied will the initialization succeed. -How does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: +So how does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: Publish-NavApp … -PublisherAzureActiveDirectoryTenantId From 3a9f1396d1be07db49b9e6ac5bf363eeb911ce82 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 1 Jul 2020 09:39:57 +0200 Subject: [PATCH 040/950] Update azure-key-vault.md --- dev-itpro/administration/azure-key-vault.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/azure-key-vault.md index 6594042889..e7a3e4e69a 100644 --- a/dev-itpro/administration/azure-key-vault.md +++ b/dev-itpro/administration/azure-key-vault.md @@ -1,6 +1,6 @@ ----""''©™®* -title: User Authentication with Azure AD for Single Sign-on -description: Associate an existing Microsoft account with user account to achieve single sign-on between the Web client and Office 365. +--- +title: Azure Key Vaults with Business Central +description: Describes how to use an Azure Key vault with Business Central extensions. ms.custom: na ms.date: 04/01/2020 ms.reviewer: na @@ -10,7 +10,7 @@ ms.topic: article ms.service: "dynamics365-business-central" author: jswymer --- -# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions +# Azure Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions Some [!INCLUDE[prodshort](../developer/includes/prodshort.md) extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md) services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. From 19cdf5e2a65cc8a69a3fc15ab873179b1ee34ab4 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 1 Jul 2020 12:36:39 +0200 Subject: [PATCH 041/950] Update azure-key-vault.md --- dev-itpro/administration/azure-key-vault.md | 134 +++++++++++++------- 1 file changed, 90 insertions(+), 44 deletions(-) diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/azure-key-vault.md index e7a3e4e69a..0e4de41f2e 100644 --- a/dev-itpro/administration/azure-key-vault.md +++ b/dev-itpro/administration/azure-key-vault.md @@ -10,7 +10,7 @@ ms.topic: article ms.service: "dynamics365-business-central" author: jswymer --- -# Azure Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions +# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions Some [!INCLUDE[prodshort](../developer/includes/prodshort.md) extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md) services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. @@ -91,7 +91,7 @@ An extension manifest can specify up to two Azure Key Vaults, like this: The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. -## Setting up Azure Key Vault for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises +## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. @@ -170,7 +170,7 @@ The steps in this task are done from the the [Azure portal](https://portal.azure From the key vault reader application overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions to locate and upload the certificate. -### Grant the key vault reader application permission to read secrets from the key vaults +### Grant the key vault reader application permission to key vaults In this task, you grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). @@ -182,78 +182,124 @@ In this task, you grant the key vault reader application permission to read secr At this point, the work in Azure is finished. -## Configure the Business Central Server +## Configure the Business Central Server for the Apps Key Vault Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. -You can configure the server instance using any of the following methods: +1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md) server computer. -- [!INCLUDE[admintool](../developer/includes/admintool.md)- -- [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration) of the [!INCLUDE[adminshell](../developer/includes/adminshell.md). -- Manually modifying the server instances CustomSetting.config file. + You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) orr [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. -For more information about using these tools, see [Configuring Business Central Server](configure-server-instance.md). - -### Required settings -The following table describes the settings that you configure to enable Azure key vault on the server instance: - -|Setting|Key name in CustomSetting.config|Value|Example| -|--------|-------------------------------|-----|-------| -|Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Specifies the certificate store location for the Key Vault client certificate.|LocalMachine| -|Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Specifies the certificate store name for the Key Vault client certificate.|MY| -|Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint||649419e4fbb87340f5a0f995e605b74c5f6d943e| -|Client ID|AzureKeyVaultClientId|Specifies the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| -|AzureKeyVaultAppSecretsPublisherValidationEnabled|false| + For example, the following PowerShell command installs a certificate to the local machine's personal store: + + ```powershell + Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My + ``` + + Make a note of the certificate thumbprint because you'll need it in the next step. For instructions on getting the thumbprint using the MMC snap-in, see [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). +2. Configure the server instance. -> [!IMPORTANT] -> Setting the AzureKeyVaultAppSecretsPublisherValidationEnabled to false means the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. + Now, you'll configure App Key Vault settings on the server instance. You can use any of the following methods: + + - [!INCLUDE[admintool](../developer/includes/admintool.md) + - [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration) of the [!INCLUDE[adminshell](../developer/includes/adminshell.md). + - Manually modifying the server instances CustomSetting.config file. + + For more information about using these tools, see [Configuring Business Central Server](configure-server-instance.md). + + The following table describes the settings that you configure to enable Azure key vault on the server instance: + + |Setting|Key name in CustomSetting.config|Value|Example| + |--------|-------------------------------|-----|-------| + |Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Set to the certificate store location where key vault certificate was stored.|LocalMachine| + |Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Set to the certificate store name where key vault certificate was stored.|MY| + |Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| + |Client ID|AzureKeyVaultClientId|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| + |Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| -At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. + > [!IMPORTANT] + > Setting the `AzureKeyVaultAppSecretsPublisherValidationEnabled` to false means the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. -At this point, you can run your extension and read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. +At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. -## Setting up Azure Key Vault for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online +## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. -Some steps are the same as for on-premises installations. You need to create one or two key vaults, and you need to adjust your extension manifest and AL code to read from these key vaults. +Some steps are the same as for on-premises installations. You need to create one or two key vaults, and you need to adjust your extension manifest and AL code to read from these key vaults. - +### Create the Azure Key Vault with secrets -Grant a Business Central SaaS AAD application permission to read secrets from your key vaults +Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. + -New-Azureadserviceprincipal +There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. -New-AzureADServicePrincipal -AppId 7e97dcfb-bcdd-426e-8f0a-96439602627a +The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](/azure/key-vault/secrets/quick-create-portal). -These step provision Microsoft's centralized AAD application into your AAD tenant, where it now "lives" together with your key vaults. +For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). -The next step is to grant the AAD application permissions to your key vaults. +### Provision the key reader application in your Azure AD tenant -Please follow the same steps as for on-premises installations, as described under "Grant the AAD application permission to read secrets from the key vaults". +Your Business Central online solution is configured to use an Azure AD application for reading key vault secrets. The application is called **Dynamics 365 Business Central ISV Key Vault Reader**. Microsoft manages the key vault reader application, however, there are a couple tasks that you have to do to enable it. First, the application must be provisioned on your Azure AD tenant, as described here. - +To provision the key vault reader application, use the [Azure Active Directory PowerShell module](/powershell/module/azuread). -Contact Microsoft to enable the App Key Vault feature for your App Source app +1. Open Windows PowerShell as an administrator. +2. Install the Azure Active Directory PowerShell module. -Please send an email to TODO@microsoft.com to start the onboarding process. This should be done before you publish your updated extension to Partner Center. + ```powershell + Install-Module AzureAD + ``` +3. Import the Azure AD module. - + ```powershell + Import-Module AzureAD + ``` +4. Connect to your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Azure AD tenant. -The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. + 1. Run the following command: - + ```powershell + Connect-AzureAD + ``` + 2. Provide your sign-in name and password when prompted. - +4. Create an Azure AD service principal using the following command: + + ```powershell + New-AzureADServicePrincipal -AppId 7e97dcfb-bcdd-426e-8f0a-96439602627a + ``` + + 7e97dcfb-bcdd-426e-8f0a-96439602627a is the Application (client) ID of Microsoft's centralized Azure AD application. + + This step provisions the application in your Azure AD tenant, where it now "lives" together with your key vaults. + +## Grant the key vault reader application permission to your key vaults + +The next task is to grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Open the key vault in the portal. +2. Select **Access policies**, then **Add Access Policy**. +3. Set **Secret Permissions** to **Get**. +4. Select **Select principal**, and on the right, search for either the application (client) ID **7e97dcfb-bcdd-426e-8f0a-96439602627a** or the display name **Dynamics 365 Business Central ISV Key Vault Reader**. +5. Select **Add**, then **Save**. + + +## Contact Microsoft to enable the App Key Vault feature + +Send an email to TODO@microsoft.com to start the onboarding process. This should be done before you publish your updated extension to Partner Center. + +The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. ## Security considerations From f606ce1878341faa1209025a03534e780d883268 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 1 Jul 2020 13:21:51 +0200 Subject: [PATCH 042/950] updates --- .../configure-server-instance.md | 30 ++++++++++++++----- dev-itpro/developer/devenv-encrypting-data.md | 2 +- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 6017285c7e..8a6bd1c0ba 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -83,7 +83,6 @@ The following table describes fields on the **General** tab in the [!INCLUDE[adm |Enable Full AL Function Tracing|EnableFullALFunctionTracing|Specifies whether full AL function tracing is enabled on Event Tracing for Windows \(ETW\) sessions.

When this setting is enabled, all AL function calls and statements are traced.

When this setting is disabled, only root AL function calls are traced. Statements and functions that are called from a function aren't traced.

For more information, see [Monitoring Business Central Server Events](monitor-server-events.md) .

Default: Not enabled
Dynamically Updatable: Yes| |Enable Incremental Company Deletion|UseIncrementalCompanyDelete|Specifies whether to delete companies incrementally. If enabled, when you delete a company, the company record is deleted from the database immediately. But the company data that is stored in the SQL tables will be deleted later by a system task in task scheduler.

You can override this setting when using the [Remove-NAVCompany cmdlet](/powershell/module/microsoft.dynamics.nav.management/remove-navcompany) by setting the -ForceImmediateDataDeletion parameter.

Default: Not enabled
Dynamically Updatable: Yes| |Enable Session While Sync Pending|AllowSessionWhileSyncPending|Specifies whether new client sessions can be created while the tenant's state is **OperationalWithSyncPending**.

The **OperationalWithSyncPending** state occurs when changes have been made to application tables, but the changes haven't been synchronized with the tenant. In this state, unless you enable client sessions, clients trying to connect with will get an error message similar to: **The tenant 'tenantID' is not accessible**.

Default: Not enabled
Dynamically Updatable: Yes| -| Encryption Key Provider |EncryptionProvider| Specifies where the encryption key used to encrypt data in the database is stored, either **LocalKeyFile** or **AzureKeyVault** values. If you use **AzureKeyVault**, see the **Azure Key Vault Encryption Provider** tab settings.

Default: LocalKeyFile
Dynamically Updatable: No| |Lockout Sign-In Attempts Count|LockoutPolicyFailedAuthenticationCount|Specifies the number of failed sign-in attempts on a user account (within the time window set by the **Lockout Failed Sign-In Attempts Window** setting) at which the user account is disabled.

Default: 0
Dynamically Updatable: No| |Lockout Failed Sign-In Attempts Window|LockoutPolicyFailedAuthenticationWindow|Specifies time window, in seconds, during which consecutive failed authentication attempts are counted. This setting works in conjunction with the **Account Lockout Max. Sign-In Attempts** setting. When the number of failed sign-in attempts by a user hits the value of the **Account Lockout Max. Sign-In Attempts** setting within this time window, the user account is disabled.

Default: 0
Dynamically Updatable: No| |Max Concurrent Calls|MaxConcurrentCalls|The maximum number of concurrent client calls that can be active on this server instance.

Range: 1 - 2,147,483,647

You can also use **MaxValue** as a value to indicate no limit.

Default: 40
Dynamically Updatable: No| @@ -221,20 +220,26 @@ The following table describes fields on the **Management Services** tab in the [ |Enable Management Services|ManagementServicesEnabled|Specifies whether [!INCLUDE[admintool](../developer/includes/admintool.md)] is enabled for this server instance.

Default: Enabled
Dynamically Updatable: No| |Port|ManagementServicesPort|The listening TCP port for the [!INCLUDE[admintool](../developer/includes/admintool.md)].

Valid range: 1 - 65535
Default: 7045
Dynamically Updatable: No| -## Azure Key Vault Encryption Provider Tab Settings +## Azure Key Vault Client Identity Tab Settings -The following table describes fields on the **Azure Key Vault Encryption Provider** tab in the [!INCLUDE[admintool](../developer/includes/admintool.md)]. +The following table describes fields on the **Azure Key Vault Client Identity** tab in the [!INCLUDE[admintool](../developer/includes/admintool.md)]. -> [!NOTE] -> These settings are used when you want to use Azure Key Vault to help encrypt data in the database. If you want to use Azure Key Vault to encrypt the connection between [!INCLUDE[server](../developer/includes/server.md)] and an Azure SQL database, you must store that key in the database. +These settings are used when you want to use Azure Key Vault to store extension secrets and data encryption keys. For more information, see [App Key Vaults](azure-key-vault.md) and [Data Encryption](../developer/devenv-encrypting-data.md). | Setting |Key Name| Description | |-----------|--------|---------------| -| Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation| Specifies the location of the certificate store for the Key Vault client certificate if you set the **Encryption Key Provider** field to **AzureKeyVault**.

**LocalMachine** specifies that the certificate is stored in a certificate store for the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

**CurrentUser** specifies that the certificate is stored in a certificate store for your account on the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

Default: LocalMachine
Dynamically Updatable: No| +| Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation| Specifies the location of the certificate store for the Key Vault client certificate.

**LocalMachine** specifies that the certificate is stored in a certificate store for the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

**CurrentUser** specifies that the certificate is stored in a certificate store for your account on the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

Default: LocalMachine
Dynamically Updatable: No| | Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName| Specifies the certificate store where the Key Vault client certificate is stored.

Default: My
Dynamically Updatable: No| | Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint| Specifies the thumbprint of the Key Vault client certificate

Default: My
Dynamically Updatable: No| | Client ID |AzureKeyVaultClientId| Specifies the unique identifier (GUID) of the Key Vault client application in Microsoft Azure.

Default: 00000000-0000-0000-0000-000000000000
Dynamically Updatable: No | -| Key URI | AzureKeyVaultKeyUri| Specifies the URI of the key in the Key Vault encryption provider setup.

Default:
Dynamically Updatable: No | + +## Azure Key Vault Extension Secrets Tab Settings + +The following table describes fields on the **Azure Key Vault Extension Secrets** tab in the [!INCLUDE[admintool](../developer/includes/admintool.md)]. + +| Setting |Key Name| Description | +|-----------|--------|---------------| +|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** enables validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** disables publisher validation. **Important** When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security Considerations](azure-key-vault.md#security).
An extension publisher's identity is specified when the extension is published.

Default: false
Dynamically Updatable: No| ## Azure Active Directory (Azure AD) Settings @@ -255,6 +260,17 @@ The settings in this tab configure the [!INCLUDE[server](../developer/includes/s | WS-Federation Login Endpoint | WSFederationLoginEndpoint| Specifies the URL for the federation sign-on page that [!INCLUDE[prodshort](../developer/includes/prodshort.md)] redirects to when configured for single sign-on.

You must specify a URL in the following format:

`https://login.microsoftonline.com/[AADTENANTID]/wsfed?wa=wsignin1.0%26wtrealm=...%26wreply=....`

The placeholder [AADTENANTID] represents the GUID of your Azure AD tenant. If the server instance has to support multiple Azure AD tenants, then the **Azure AD Tenant ID** parameter that is specified when mounting a tenant replaces the placeholder.

Default:
Dynamically Updatable: No| | WS-Federation Metadata Location | ClientServicesFederationMetadataLocation| Specifies the URL for the federation metadata document that describes the configuration information for your Azure AD tenant. The federation metadata document is used to validate the security tokens that the [!INCLUDE[nav_web](../developer/includes/nav_web_md.md)] and [!INCLUDE[nav_tablet](../developer/includes/nav_tablet_md.md)] receive, and to establish a trust relationship with between [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and an application that you've added to Azure AD.

You must specify a URL in the following format:

`https://login.microsoftonline.com/[AADTENANTID]/FederationMetadata/2007-06/FederationMetadata.xml`

The placeholder [AADTENANTID] represents the GUID of your Azure AD tenant. If the server instance has to support multiple Azure AD tenants, then the Azure AD Tenant ID parameter that is specified when mounting a tenant replaces the placeholder.

This parameter is relevant only when **Credential Type**, on the **General** tab, is set to **AccessControlService**. For more information, see [Authenticating Users with Azure Active Directory](Authenticating-Users-with-Azure-Active-Directory.md).

Default:
Dynamically Updatable: No| +## Data Encryption Settings + +The following table describes fields on the **Data Encryption** tab in the [!INCLUDE[admintool](../developer/includes/admintool.md)]. + +For more information about data encyrption, see [Data Encryption](../developer/devenv-encrypting-data.md). + +| Setting |Key Name| Description | +|-----------|--------|---------------| +| Encryption Key Provider |EncryptionProvider| Specifies where the encryption key used to encrypt data in the database is stored, either **LocalKeyFile** or **AzureKeyVault** values. If you use **AzureKeyVault**, see the **Azure Key Vault Encryption Provider** tab settings.

Default: LocalKeyFile
Dynamically Updatable: No| +| Key URI | AzureKeyVaultKeyUri| Specifies the URI of the key in the Key Vault encryption provider setup.

Default:
Dynamically Updatable: No | + ## Task Scheduler Settings The following table describes fields on the **Task Scheduler** tab in the [!INCLUDE[admintool](../developer/includes/admintool.md)]. diff --git a/dev-itpro/developer/devenv-encrypting-data.md b/dev-itpro/developer/devenv-encrypting-data.md index bd1ead522d..880dd32a1f 100644 --- a/dev-itpro/developer/devenv-encrypting-data.md +++ b/dev-itpro/developer/devenv-encrypting-data.md @@ -1,4 +1,4 @@ ---- +[Data Encryption](../developer/devenv-encrypting-data.md).--- title: "Encrypting Data in Dynamics 365 for Business Central" ms.custom: na ms.date: 04/01/2020 From 2fe8a5056eeb8b44f1013b0e71eecd5787c41dea Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 1 Jul 2020 13:24:34 +0200 Subject: [PATCH 043/950] Update azure-key-vault.md --- dev-itpro/administration/azure-key-vault.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/azure-key-vault.md index 0e4de41f2e..3739cd8054 100644 --- a/dev-itpro/administration/azure-key-vault.md +++ b/dev-itpro/administration/azure-key-vault.md @@ -223,11 +223,9 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. -## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online +## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online -In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. - -Some steps are the same as for on-premises installations. You need to create one or two key vaults, and you need to adjust your extension manifest and AL code to read from these key vaults. +In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. ### Create the Azure Key Vault with secrets From d9659b466c6aa3444cca941419d221cad786d328 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 1 Jul 2020 15:50:36 +0200 Subject: [PATCH 044/950] updates --- dev-itpro/administration/configure-server-instance.md | 4 ++-- .../{azure-key-vault.md => extension-key-vault.md} | 0 dev-itpro/developer/devenv-json-files.md | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) rename dev-itpro/administration/{azure-key-vault.md => extension-key-vault.md} (100%) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 8a6bd1c0ba..0537db4039 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -224,7 +224,7 @@ The following table describes fields on the **Management Services** tab in the [ The following table describes fields on the **Azure Key Vault Client Identity** tab in the [!INCLUDE[admintool](../developer/includes/admintool.md)]. -These settings are used when you want to use Azure Key Vault to store extension secrets and data encryption keys. For more information, see [App Key Vaults](azure-key-vault.md) and [Data Encryption](../developer/devenv-encrypting-data.md). +These settings are used when you want to use Azure Key Vault to store extension secrets and data encryption keys. For more information, see [Extension Key Vaults](extension-key-vault.md) and [Data Encryption](../developer/devenv-encrypting-data.md). | Setting |Key Name| Description | |-----------|--------|---------------| @@ -239,7 +239,7 @@ The following table describes fields on the **Azure Key Vault Extension Secrets* | Setting |Key Name| Description | |-----------|--------|---------------| -|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** enables validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** disables publisher validation. **Important** When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security Considerations](azure-key-vault.md#security).
An extension publisher's identity is specified when the extension is published.

Default: false
Dynamically Updatable: No| +|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** enables validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** disables publisher validation. **Important** When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security Considerations](extension-key-vault.md#security).
An extension publisher's identity is specified when the extension is published.

Default: false
Dynamically Updatable: No| ## Azure Active Directory (Azure AD) Settings diff --git a/dev-itpro/administration/azure-key-vault.md b/dev-itpro/administration/extension-key-vault.md similarity index 100% rename from dev-itpro/administration/azure-key-vault.md rename to dev-itpro/administration/extension-key-vault.md diff --git a/dev-itpro/developer/devenv-json-files.md b/dev-itpro/developer/devenv-json-files.md index 7e6f56364c..e4081953fb 100644 --- a/dev-itpro/developer/devenv-json-files.md +++ b/dev-itpro/developer/devenv-json-files.md @@ -41,6 +41,7 @@ The following table describes the settings in the `app.json` file: |application|Yes, if base application is referenced in the extension|The supported version of the system and base application package file, for example: "16.0.0.0". The file name of this reference is Microsoft_Application.app and the `name` is `Application`. For code-customized base applications, the Microsoft_Application.app file can be modified to reference the code-customized base application instead. It is important to keep `"name": "Application"` in the extension, but information about publisher can be changed and the .app file can be renamed. For more information, see [The Microsoft_Application.app File](devenv-application-app-file.md).| |idRange|Yes|For example: `"idRange": {"from": 50100,"to": 50149}`. A range for application object IDs. For all objects outside the range, a compilation error will be raised. When you create new objects, an ID is automatically suggested.| |idRanges|Yes|For example: `"idRanges": [{"from": 50100,"to": 50200},{"from": 50202,"to": 50300}]`. A list of ranges for application object IDs. For all objects outside the ranges, a compilation error will be raised. When you create new objects, an ID is automatically suggested. You must use *either* the `idRange` *or* the `idRanges` setting. Overlapping ranges are not allowed and will result in a compilation error. | +|keyVaultUrls|No|List of URLs of key vaults that the extension from which the extension can retrieve secrets. For example: `"keyVaultUrls": [ "https://myfirstkeyvault.vault.azure.net", "https://mysecondkeyvault.vault.azure.net" ]`.

For more information, see [App Key Vaults](../administration/extension-key-vault.md). |showMyCode|No|This is by default set to `false` and not visible in the manifest. To enable viewing the source code when debugging into an extension, add the following setting: `"showMyCode": true`| |target|No|By default this is `Cloud`. The setting currently has the following options: `Internal`, `Extension`, `OnPrem`, and `Cloud`. The `Internal` and `Extension` settings are being deprecated with runtime 4.0 and replaced by the `OnPrem` and `Cloud` respectively. For on-premises, you can set this to `OnPrem` to get access to otherwise restricted APIs and .NET Interop. The Business Central Server setting must then also be set to `OnPrem`. **Note:** System tables that have the [Scope](properties/devenv-scope-property.md) property set to `Internal`/`OnPrem` cannot be accessed from extensions that have `target` set to `Cloud`/`External` through direct reference or through RecordRef. For more information, see [Compilation Scope Overview](devenv-compilation-scope-overview.md)| |contextSensitiveHelpUrl|No, but required for AppSource submission|The URL for the website that displays context-sensitive Help for the objects in the app, such as `https://mysite.com/documentation/`. If the app does not support all locales currently supported by [!INCLUDE [prodshort](includes/prodshort.md)], then include a parameter for the locale in this URL, `/{0}/`, and also specify the relevant locales in the `supportedLocales` setting.| From 8ffe304d426f1d41c87ab8e5e0becf3bea4fec41 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 2 Jul 2020 08:47:31 +0200 Subject: [PATCH 045/950] Update extension-key-vault.md --- dev-itpro/administration/extension-key-vault.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 3739cd8054..b36044c3df 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -188,15 +188,15 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) 1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md) server computer. - You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) orr [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. + 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) orr [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. - For example, the following PowerShell command installs a certificate to the local machine's personal store: + For example, the following PowerShell command installs a certificate to the local machine's personal store: - ```powershell - Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My - ``` - - Make a note of the certificate thumbprint because you'll need it in the next step. For instructions on getting the thumbprint using the MMC snap-in, see [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). + ```powershell + Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My + ``` + + 2. Make a note of the certificate thumbprint because you'll need it in the next step. For instructions on getting the thumbprint using the MMC snap-in, see [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). 2. Configure the server instance. From 28cb3d26ae747f7f8814645d75aaca0a085310ff Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 2 Jul 2020 09:14:36 +0200 Subject: [PATCH 046/950] Update configure-server-instance.md --- dev-itpro/administration/configure-server-instance.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 6017285c7e..8e0062c66d 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -295,6 +295,7 @@ The following table describes fields on the **Reports** tab in the [!INCLUDE[adm | Enable Save as Word on Request Pages of RDLC-layout Reports | EnableSaveToWordForRdlcReports| Specifies whether users can open or save a report as a Microsoft Word document if the report uses an RDLC layout.

If you clear this check box, the **Word** option is removed from the **Print** menu on the request page.

Default: Enabled
Dynamically Updatable: No| | Enable Save from Report Preview | EnableSaveFromReportPreview| Specifies whether users can save a report as a PDF, Microsoft Word, or Microsoft Excel document from the report preview window.

If you clear this check box, the **Save As** icon is removed from the report preview window.

Default: Enabled
Dynamically Updatable: No| | Enforce Cloud Print Support | ReportCloudPrintingEnforced | Specifies whether cloud printing is supported for reports. This setting must be enabled to send print jobs to any printer that is set up by an extension that subscribes to the OnAfterDocumentPrintReady event.

If you disable this setting, the OnAfterDocumentPrintReady event is never raised, and print jobs are directed to the default printing on the server.

Default: Enabled
Dynamically Updatable: No| +| Max Dcouments | ReportMaxDocuments | Specifies the maximum number of documents that can be merged when using [WordMergeDataItem](../developer/properties/devenv-wordmergedataitem-property.md) property on reports using a Word layout. If exceeded, the report will be canceled by the server. To turn off this limit set the value to **MaxValue**.

Timeout format: [dd.]hh:mm:ss[.ff]

Default: MaxValue
Dynamically Updatable: Yes| | Max Execution Timeout | ReportTimeout | Specifies the maximum execution time that it can take to generate a report. If exceeded, the report will be canceled by the server. If you don't want a limit, set the value to **MaxValue**.

For more information about how reports are canceled, see [Report Generation and Cancellation Flow](report-cancellation.md).

Timeout format: [dd.]hh:mm:ss[.ff]

Default: MaxValue
Dynamically Updatable: Yes| | Max Rows | ReportMaxRows | Specifies the maximum number of rows that can be processed in a report. If exceeded, the report will be canceled by the server. You can also use MaxValue to indicate no limit. If you don't want a limit, set the value to **MaxValue**.

For more information about how reports are canceled, see [Report Generation and Cancellation Flow](report-cancellation.md).

Default: MaxValue
Dynamically Updatable: Yes| | Report PDF Font Embedding |ReportPDFFontEmbedding| Specifies whether fonts are embedded in PDF files that are generated for reports when the report uses an RDLC report layout at runtime. This setting applies when reports are run and saved as PDF files on the client (from the report request page or print preview window) or on the server instance (by the [SAVEAS function](../developer/methods/devenv-SAVEAS-method.md) or [SAVEASPDF function](../developer/methods/devenv-SAVEASPDF-method-Report.md) in AL code).

**Note:** This setting doesn't apply when a report uses a Word report layout at runtime.

You embed fonts in a PDF of a report to make sure that the PDF will use the same fonts as the original file, no matter where the PDF is opened and which fonts are installed on the computer. However, embedding fonts can significantly increase the size of the PDF files. Disabling font embedding decreases the size of the report PDF files.

**Note:** This setting is a global setting for font embedding in report PDF files. You can override this setting on a report basis by the specifying the [PDFFontEmbedding property](../developer/properties/devenv-PDFFontEmbedding-Property.md).

Default: Enabled
Dynamically Updatable: No| From 5ce56db279003543efb15c52ef30bd1b1d394eef Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 2 Jul 2020 13:52:37 +0200 Subject: [PATCH 047/950] updayes --- .../administration/telemetry-event-ids.md | 2 + .../telemetry-extension-key-vault-trace.md | 195 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 dev-itpro/administration/telemetry-extension-key-vault-trace.md diff --git a/dev-itpro/administration/telemetry-event-ids.md b/dev-itpro/administration/telemetry-event-ids.md index e66f71a374..fe2c5f24a2 100644 --- a/dev-itpro/administration/telemetry-event-ids.md +++ b/dev-itpro/administration/telemetry-event-ids.md @@ -31,6 +31,8 @@ The following tables list the IDs of [!INCLUDE[prodshort](../developer/includes/ |RT0010|Extension lifecycle|[Extension Update Failed: exception raised in extension {extensionName} by {extensionPublisher} (updating to version {extensionTargetedVersion})](telemetry-extension-update-trace.md#extension-update-failed-exception-raised-in-extension) | | RT0012 | Performance | [Database lock timed out](telemetry-database-locks-trace.md#database-lock-timed-out) | | RT0013 | Performance | [Database lock snapshot: {snapshotId}](telemetry-database-locks-trace.md#database-lock-snapshot) | +| RT0017 | Performance | [Database lock snapshot: {snapshotId}](telemetry-database-locks-trace.md#database-lock-snapshot) | + ## Lifecycle events diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md new file mode 100644 index 0000000000..cb0dcf070f --- /dev/null +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -0,0 +1,195 @@ +--- +title: Extension Update Trace Telemetry | Microsoft Docs +description: Learn about the extension upgrade telemetry in Business Central +author: jswymer +ms.service: dynamics365-business-central +ms.topic: article +ms.devlang: na +ms.tgt_pltfrm: na +ms.workload: na +ms.search.keywords: administration, tenant, admin, environment, sandbox, telemetry +ms.date: 05/10/2020 +ms.author: jswymer +--- +# Analyzing Extension Update Trace Telemetry + +**INTRODUCED IN:** Business Central 2020 release wave 2 + +App key vault telemetry gathers information about the acquisition of secrets in Azure Key Vaults by extensions at runtime. Extensions can be configured to retrieve secrets from one or key vaults. + +The gathered data can help you identify, troubleshoot, and resolve issues with per-tenant extensions. For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). + +## App Key Vault secret initialization succeeded + +Occurs when an extension secret was successfully initialized. + +### General dimensions + +|Dimension|Description or value| +|---------|-----| +|message|**App Key Vault initialization succeeded: '{keVaultUri}'.**| +|severityLevel|**1**| + +### Custom dimensions + +|Dimension|Description or value| +|---------|-----| +|aadTenantId|Specifies that Azure Active Directory (Azure AD) tenant ID used for Azure AD authentication. For on-premises, if you aren't using Azure AD authentication, this value is **common**. | +|alObjectId|Specifies the ID of the AL object that was run by request.| +|alObjectName|Specifies the name of the AL object that was run by request.| +|alObjectType|Specifies the type of AL object that was run by request.| +|alStackTrace|The stack trace in AL.| +|clientType|Specifies the type of client that executed the SQL Statement, such as **Background** or **Web**. For a list of the client types, see [ClientType Option Type](../developer/methods-auto/clienttype/clienttype-option.md).| +|companyName|The display name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] company that was used at time of execution. || +|component|**Dynamics 365 Business Central Server**.| +|componentVersion|Specifies the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] version number.| +|deprecatedKeys|A comma-separated list of all the keys that have been deprecated. The keys in this list are still supported but will eventually be removed in the next major release. We recommend that update any queries that use these keys to use the new key name.| +|environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| +|environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| +|eventId|**RT0014**| +|extensionName|Specifies the name of the extension.| +|extensionId|Specifies the AppID of the extension.| +|extensionPublisher|Specifies the publisher of the extension| +|extensionVersion|Specifies the version of the extension.| +|keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| +|telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| + + + +## App Key Vault initialization failed + +Occurs when a key vault failed to be initialized. + +### General dimensions + +|Dimension|Description or value| +|---------|-----| +|message|**App Key Vault initialization failed.**| +|severityLevel|**3**| + +### Custom dimensions + +|Dimension|Description or value| +|---------|-----| +|aadTenantId|Specifies that Azure Active Directory (Azure AD) tenant ID used for Azure AD authentication. For on-premises, if you aren't using Azure AD authentication, this value is **common**. | +|alObjectId|Specifies the ID of the AL object that was run by request.| +|alObjectName|Specifies the name of the AL object that was run by request.| +|alObjectType|Specifies the type of AL object that was run by request.| +|alStackTrace|The stack trace in AL.| +|clientType|Specifies the type of client that executed the SQL Statement, such as **Background** or **Web**. For a list of the client types, see [ClientType Option Type](../developer/methods-auto/clienttype/clienttype-option.md).| +|companyName|The display name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] company that was used at time of execution. || +|component|**Dynamics 365 Business Central Server**.| +|componentVersion|Specifies the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] version number.| +|deprecatedKeys|A comma-separated list of all the keys that have been deprecated. The keys in this list are still supported but will eventually be removed in the next major release. We recommend that update any queries that use these keys to use the new key name.| +|environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| +|environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| +|eventId|**RT0015**| +|extensionName|Specifies the name of the extension.| +|extensionId|Specifies the AppID of the extension.| +|extensionPublisher|Specifies the publisher of the extension| +|extensionVersion|Specifies the version of the extension.| +|failureReason|Specifies the error that occurred.| +|telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| + + + +## App Key Vault secret retrieval succeeded + +Occurs when a secret used by an extension is successfully retrieved from an Azure Key Vault. + +### General dimensions + +|Dimension|Description or value| +|---------|-----| +|message|**App Key Vault secret retrieval succeeded from key vault '{keVaultUri}'.**| +|severityLevel|**1**| + +### Custom dimensions + +|Dimension|Description or value| +|---------|-----| +|aadTenantId|Specifies that Azure Active Directory (Azure AD) tenant ID used for Azure AD authentication. For on-premises, if you aren't using Azure AD authentication, this value is **common**. | +|alObjectId|Specifies the ID of the AL object that was run by request.| +|alObjectName|Specifies the name of the AL object that was run by request.| +|alObjectType|Specifies the type of AL object that was run by request.| +|alStackTrace|The stack trace in AL.| +|clientType|Specifies the type of client that executed the SQL Statement, such as **Background** or **Web**. For a list of the client types, see [ClientType Option Type](../developer/methods-auto/clienttype/clienttype-option.md).| +|companyName|The display name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] company that was used at time of execution. || +|component|**Dynamics 365 Business Central Server**.| +|componentVersion|Specifies the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] version number.| +|deprecatedKeys|A comma-separated list of all the keys that have been deprecated. The keys in this list are still supported but will eventually be removed in the next major release. We recommend that update any queries that use these keys to use the new key name.| +|environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| +|environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| +|eventId|**RT0016**| +|extensionName|Specifies the name of the extension.| +|extensionId|Specifies the AppID of the extension.| +|extensionPublisher|Specifies the publisher of the extension| +|extensionVersion|Specifies the version of the extension.| +|keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| +|telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| + + + +## App Key Vault secret retrieval failed + +Occurs when an extension failed to retrieve a secret from a specified Azure key vault. + +### General dimensions + +|Dimension|Description or value| +|---------|-----| +|message|**App Key Vault secret retrieval failed from key vault '{keVaultUri}'.**| +|severityLevel|**3**| + +### Custom dimensions + +|Dimension|Description or value| +|---------|-----| +|aadTenantId|Specifies that Azure Active Directory (Azure AD) tenant ID used for Azure AD authentication. For on-premises, if you aren't using Azure AD authentication, this value is **common**. | +|alObjectId|Specifies the ID of the AL object that was run by request.| +|alObjectName|Specifies the name of the AL object that was run by request.| +|alObjectType|Specifies the type of AL object that was run by request.| +|alStackTrace|The stack trace in AL.| +|clientType|Specifies the type of client that executed the SQL Statement, such as **Background** or **Web**. For a list of the client types, see [ClientType Option Type](../developer/methods-auto/clienttype/clienttype-option.md).| +|companyName|The display name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] company that was used at time of execution. || +|component|**Dynamics 365 Business Central Server**.| +|componentVersion|Specifies the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] version number.| +|deprecatedKeys|A comma-separated list of all the keys that have been deprecated. The keys in this list are still supported but will eventually be removed in the next major release. We recommend that update any queries that use these keys to use the new key name.| +|environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| +|environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| +|eventId|**RT0017**| +|extensionName|Specifies the name of the extension.| +|extensionId|Specifies the AppID of the extension.| +|extensionPublisher|Specifies the publisher of the extension| +|extensionVersion|Specifies the version of the extension.| +|failureReason|Specifies the error that occurred.| +|keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| +|telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| + +### Troubleshooting failures + + + +## See also + +[Upgrading Extensions](../developer/devenv-upgrading-extensions.md) +[Monitoring and Analyzing Telemetry](telemetry-overview.md) +[Enabling Application Insights for Tenant Telemetry On-Premises](telemetry-enable-application-insights.md) +[Enable Sending Telemetry to Application Insights](tenant-admin-center-telemetry.md#appinsights) From 4b59befe04222bb272c1d96cdab7e5d8754a22ae Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 2 Jul 2020 17:57:29 +0200 Subject: [PATCH 048/950] Update telemetry-extension-key-vault-trace.md --- dev-itpro/administration/telemetry-extension-key-vault-trace.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md index cb0dcf070f..8db76f2a22 100644 --- a/dev-itpro/administration/telemetry-extension-key-vault-trace.md +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -17,6 +17,7 @@ ms.author: jswymer App key vault telemetry gathers information about the acquisition of secrets in Azure Key Vaults by extensions at runtime. Extensions can be configured to retrieve secrets from one or key vaults. +There are various reasons retrieving secret might fail, for example, The gathered data can help you identify, troubleshoot, and resolve issues with per-tenant extensions. For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). ## App Key Vault secret initialization succeeded @@ -139,7 +140,6 @@ Occurs when a secret used by an extension is successfully retrieved from an Azur ## App Key Vault secret retrieval failed From 61321afea056d7e830b1548f67ab5ef08a717dd8 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 2 Jul 2020 19:10:14 +0200 Subject: [PATCH 049/950] Update telemetry-extension-key-vault-trace.md --- .../telemetry-extension-key-vault-trace.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md index 8db76f2a22..a6d2cda0f0 100644 --- a/dev-itpro/administration/telemetry-extension-key-vault-trace.md +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -1,5 +1,5 @@ --- -title: Extension Update Trace Telemetry | Microsoft Docs +title: App Key Vault Secret Trace Telemetry | Microsoft Docs description: Learn about the extension upgrade telemetry in Business Central author: jswymer ms.service: dynamics365-business-central @@ -11,7 +11,7 @@ ms.search.keywords: administration, tenant, admin, environment, sandbox, telemet ms.date: 05/10/2020 ms.author: jswymer --- -# Analyzing Extension Update Trace Telemetry +# Analyzing App Key Vault Secret Trace Telemetry **INTRODUCED IN:** Business Central 2020 release wave 2 @@ -28,7 +28,7 @@ Occurs when an extension secret was successfully initialized. |Dimension|Description or value| |---------|-----| -|message|**App Key Vault initialization succeeded: '{keVaultUri}'.**| +|message|**App Key Vault initialization succeeded: '{keyVaultUri}'.**| |severityLevel|**1**| ### Custom dimensions @@ -111,7 +111,7 @@ Occurs when a secret used by an extension is successfully retrieved from an Azur |Dimension|Description or value| |---------|-----| -|message|**App Key Vault secret retrieval succeeded from key vault '{keVaultUri}'.**| +|message|**App Key Vault secret retrieval succeeded from key vault '{keyVaultUri}'.**| |severityLevel|**1**| ### Custom dimensions @@ -150,7 +150,7 @@ Occurs when an extension failed to retrieve a secret from a specified Azure key |Dimension|Description or value| |---------|-----| -|message|**App Key Vault secret retrieval failed from key vault '{keVaultUri}'.**| +|message|**App Key Vault secret retrieval failed from key vault '{keyVaultUri}'.**| |severityLevel|**3**| ### Custom dimensions From 4e4a61586150e48969442e8a87c18447242520f5 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 2 Jul 2020 19:30:01 +0200 Subject: [PATCH 050/950] updates --- dev-itpro/TOC.md | 1 + dev-itpro/administration/telemetry-event-ids.md | 6 ++++-- .../administration/telemetry-extension-key-vault-trace.md | 8 ++++---- dev-itpro/administration/telemetry-overview.md | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 41510e7bef..81b4284a4b 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -75,6 +75,7 @@ ### [Prepare for Major Updates with Preview Environments](administration/preview-environments.md) ## Monitoring and Analyzing Telemetry ### [Overview](administration/telemetry-overview.md) +### [App Key Vault Secret Telemetry](administration/telemetry-extension-key-vault-trace.md) ### [Authorization Telemetry](administration/telemetry-authorization-trace.md) ### [Company Lifecycle Telemetry](administration/telemetry-company-lifecycle-trace.md) ### [Database Lock Timeout Telemetry](administration/telemetry-database-locks-trace.md) diff --git a/dev-itpro/administration/telemetry-event-ids.md b/dev-itpro/administration/telemetry-event-ids.md index fe2c5f24a2..ed2c5e9443 100644 --- a/dev-itpro/administration/telemetry-event-ids.md +++ b/dev-itpro/administration/telemetry-event-ids.md @@ -31,8 +31,10 @@ The following tables list the IDs of [!INCLUDE[prodshort](../developer/includes/ |RT0010|Extension lifecycle|[Extension Update Failed: exception raised in extension {extensionName} by {extensionPublisher} (updating to version {extensionTargetedVersion})](telemetry-extension-update-trace.md#extension-update-failed-exception-raised-in-extension) | | RT0012 | Performance | [Database lock timed out](telemetry-database-locks-trace.md#database-lock-timed-out) | | RT0013 | Performance | [Database lock snapshot: {snapshotId}](telemetry-database-locks-trace.md#database-lock-snapshot) | -| RT0017 | Performance | [Database lock snapshot: {snapshotId}](telemetry-database-locks-trace.md#database-lock-snapshot) | - +| RT0014 | Security | [App Key Vault initialization succeeded: '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#initializedsuccess) | +| RT0015 | Security | [App Key Vault initialization failed](telemetry-extension-key-vault-trace.md#initializedfailed) | +| RT0016 | Security | [App Key Vault secret retrieval succeeded from key vault '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#retrievedsuccess) | +| RT0017 | Security | [App Key Vault secret retrieval failed from key vault: '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#retrievedfailed) | ## Lifecycle events diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md index a6d2cda0f0..d0970d4bba 100644 --- a/dev-itpro/administration/telemetry-extension-key-vault-trace.md +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -20,7 +20,7 @@ App key vault telemetry gathers information about the acquisition of secrets in There are various reasons retrieving secret might fail, for example, The gathered data can help you identify, troubleshoot, and resolve issues with per-tenant extensions. For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). -## App Key Vault secret initialization succeeded +## App Key Vault secret initialization succeeded Occurs when an extension secret was successfully initialized. @@ -61,7 +61,7 @@ Example: {"Component":"Dynamics 365 Business Central Server","Telemetry schema version":"0.1","telemetrySchemaVersion":"0.1","Component version":"16.0.14248.0","componentVersion":"16.0.14248.0","deprecatedKeys":"Company name, AL Object Id, AL Object type, AL Object name, AL Stack trace, Client type, Extension name, Extension App Id, Extension version, Telemetry schema version, Component, Component version, Extension name, Extension App Id, Extension version, Telemetry schema version","extensionPublisher":"Microsoft","Extension version":"17.0.14320.0","extensionVersion":"17.0.14320.0","Extension App Id":"63ca2fa4-4f03-4f2b-a480-172fef340d3f","component":"Dynamics 365 Business Central Server","Extension name":"System Application","extensionName":"System Application","AL Object Id":"3801","Company name":"CRONUS International Ltd.","eventId":"RT0014","Client type":"WebClient","companyName":"CRONUS International Ltd.","extensionId":"63ca2fa4-4f03-4f2b-a480-172fef340d3f","alObjectId":"3801","clientType":"WebClient","AL Object type":"CodeUnit","AL Stack trace":"AppObjectType: CodeUnit\r\n AppObjectId: 3801\r\n AL CallStack: \"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentAppInternal - System Application by Microsoft\r\n\"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentApp - System Application by Microsoft\r\n\"App Key Vault Secret Provider\"(CodeUnit 3800).TryInitializeFromCurrentApp - System Application by Microsoft\r\nHelloWorldPage(Page 50100).OnOpenPage(Trigger) line 4 - ALProject1 by Default publisher","AL Object name":"App Key Vault Secret Pr. Impl.","alStackTrace":"AppObjectType: CodeUnit\r\n AppObjectId: 3801\r\n AL CallStack: \"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentAppInternal - System Application by Microsoft\r\n\"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentApp - System Application by Microsoft\r\n\"App Key Vault Secret Provider\"(CodeUnit 3800).TryInitializeFromCurrentApp - System Application by Microsoft\r\nHelloWorldPage(Page 50100).OnOpenPage(Trigger) line 4 - ALProject1 by Default publisher","alObjectType":"CodeUnit","alObjectName":"App Key Vault Secret Pr. Impl.","keyVaultUrls":"https://jswymer-keyvault-z.vault.azure.net/"} --> -## App Key Vault initialization failed +## App Key Vault initialization failed Occurs when a key vault failed to be initialized. @@ -103,7 +103,7 @@ Occurs when a key vault failed to be initialized. {"Telemetry schema version":"0.1","telemetrySchemaVersion":"0.1","Component version":"16.0.14248.0","componentVersion":"16.0.14248.0","deprecatedKeys":"Company name, AL Object Id, AL Object type, AL Object name, AL Stack trace, Client type, Extension name, Extension App Id, Extension version, Telemetry schema version, Component, Component version, Extension name, Extension App Id, Extension version, Telemetry schema version","Component":"Dynamics 365 Business Central Server","component":"Dynamics 365 Business Central Server","AL Object Id":"3801","Company name":"CRONUS International Ltd.","Client type":"WebClient","companyName":"CRONUS International Ltd.","eventId":"RT0015","clientType":"WebClient","alObjectId":"3801","extensionPublisher":"Microsoft","Extension version":"17.0.14320.0","extensionVersion":"17.0.14320.0","Extension App Id":"63ca2fa4-4f03-4f2b-a480-172fef340d3f","Extension name":"System Application","extensionName":"System Application","extensionId":"63ca2fa4-4f03-4f2b-a480-172fef340d3f","AL Object name":"App Key Vault Secret Pr. Impl.","alObjectName":"App Key Vault Secret Pr. Impl.","alObjectType":"CodeUnit","failureReason":"No key vaults specified for extension 'ALProject4 by Me 1.0.0.3'.","alStackTrace":"AppObjectType: CodeUnit\r\n AppObjectId: 3801\r\n AL CallStack: \"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentAppInternal - System Application by Microsoft\r\n\"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentApp - System Application by Microsoft\r\n\"App Key Vault Secret Provider\"(CodeUnit 3800).TryInitializeFromCurrentApp - System Application by Microsoft\r\nHelloWorldPage(Page 50103).OnOpenPage(Trigger) line 4 - ALProject4 by Me","AL Object type":"CodeUnit","AL Stack trace":"AppObjectType: CodeUnit\r\n AppObjectId: 3801\r\n AL CallStack: \"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentAppInternal - System Application by Microsoft\r\n\"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).InitializeFromCurrentApp - System Application by Microsoft\r\n\"App Key Vault Secret Provider\"(CodeUnit 3800).TryInitializeFromCurrentApp - System Application by Microsoft\r\nHelloWorldPage(Page 50103).OnOpenPage(Trigger) line 4 - ALProject4 by Me"} --> -## App Key Vault secret retrieval succeeded +## App Key Vault secret retrieval succeeded Occurs when a secret used by an extension is successfully retrieved from an Azure Key Vault. @@ -142,7 +142,7 @@ Occurs when a secret used by an extension is successfully retrieved from an Azur {"Component":"Dynamics 365 Business Central Server","Telemetry schema version":"0.1","telemetrySchemaVersion":"0.1","Component version":"16.0.14248.0","componentVersion":"16.0.14248.0","deprecatedKeys":"Company name, AL Object Id, AL Object type, AL Object name, AL Stack trace, Client type, Extension name, Extension App Id, Extension version, Telemetry schema version, Component, Component version, Extension name, Extension App Id, Extension version, Telemetry schema version","extensionPublisher":"Microsoft","Company name":"CRONUS International Ltd.","AL Object Id":"3801","Extension version":"17.0.14320.0","Extension App Id":"63ca2fa4-4f03-4f2b-a480-172fef340d3f","extensionVersion":"17.0.14320.0","Client type":"WebClient","companyName":"CRONUS International Ltd.","component":"Dynamics 365 Business Central Server","alObjectId":"3801","clientType":"WebClient","Extension name":"System Application","extensionName":"System Application","eventId":"RT0016","extensionId":"63ca2fa4-4f03-4f2b-a480-172fef340d3f","AL Object name":"App Key Vault Secret Pr. Impl.","AL Stack trace":"AppObjectType: CodeUnit\r\n AppObjectId: 3801\r\n AL CallStack: \"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).GetSecret - System Application by Microsoft\r\n\"App Key Vault Secret Provider\"(CodeUnit 3800).GetSecret - System Application by Microsoft\r\nHelloWorldPage(Page 50103).OnOpenPage(Trigger) line 6 - ALProject4 by Me","AL Object type":"CodeUnit","alObjectName":"App Key Vault Secret Pr. Impl.","alObjectType":"CodeUnit","alStackTrace":"AppObjectType: CodeUnit\r\n AppObjectId: 3801\r\n AL CallStack: \"App Key Vault Secret Pr. Impl.\"(CodeUnit 3801).GetSecret - System Application by Microsoft\r\n\"App Key Vault Secret Provider\"(CodeUnit 3800).GetSecret - System Application by Microsoft\r\nHelloWorldPage(Page 50103).OnOpenPage(Trigger) line 6 - ALProject4 by Me","keyVaultUrl":"https://jswymer-keyvault-1.vault.azure.net/"} --> -## App Key Vault secret retrieval failed +## App Key Vault secret retrieval failed Occurs when an extension failed to retrieve a secret from a specified Azure key vault. diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 9c2218313a..ee6346116d 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -29,6 +29,7 @@ In Application Insights, telemetry from [!INCLUDE[prodshort](../developer/includ |Authorization|Provides information about user sign-in attempts. Information includes success or failure indication, reason for failure, user type, and more.|Online|[Analyzing Authentication Telemetry](telemetry-authorization-trace.md) | |Company lifecycle|Provides information about creating, copying, and deleting of companies.|Both|[Analyzing Company Lifecycle Telemetry](telemetry-company-lifecycle-trace.md) | |Database lock timeouts|Provides information about database locks that have timed out. |Both|[Database Lock Timeout Telemetry](telemetry-database-locks-trace.md)| +|App Key Vault secrets |Provides information about the retrieval of secrets from Azure Key Vaults by extensions.|Both|[Analyzing App Key Vault Secret Trace Telemetry](telemetry-extension-key-vault-trace.md) | |Extension update|Provides information about errors that occur when upgrading an extension.|Both|[Analyzing Extension Upgrade Telemetry](telemetry-extension-update-trace.md) | |Long running operation (SQL query)|Provides information about SQL queries that take longer than expected to execute.|Both|[Analyzing Long Running Operation (SQL Query) Telemetry](telemetry-long-running-sql-query-trace.md)| |Report generation|Provides information about the execution of reports.|Both|[Analyzing Report Generation Telemetry](telemetry-reports-trace.md)| From 9073022c898f6f463bcd7ba33ccef4ae095df78d Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 2 Jul 2020 19:34:52 +0200 Subject: [PATCH 051/950] Update extension-key-vault.md --- dev-itpro/administration/extension-key-vault.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index b36044c3df..246e5bb2d6 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -20,7 +20,6 @@ The credential is a kind of secret. It is secret to the extension. It shouldn't Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. - ## Specifying Azure Key Vault in extensions To use an Azure Key Vault for an extension, you specify the key vault the extension's manifest file (app.json), like this: @@ -182,7 +181,7 @@ In this task, you grant the key vault reader application permission to read secr At this point, the work in Azure is finished. -## Configure the Business Central Server for the Apps Key Vault +### Configure the Business Central Server for the Apps Key Vault Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. @@ -282,7 +281,7 @@ To provision the key vault reader application, use the [Azure Active Directory P This step provisions the application in your Azure AD tenant, where it now "lives" together with your key vaults. -## Grant the key vault reader application permission to your key vaults +### Grant the key vault reader application permission to your key vaults The next task is to grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). @@ -292,8 +291,7 @@ The next task is to grant the key vault reader application permission to read se 4. Select **Select principal**, and on the right, search for either the application (client) ID **7e97dcfb-bcdd-426e-8f0a-96439602627a** or the display name **Dynamics 365 Business Central ISV Key Vault Reader**. 5. Select **Add**, then **Save**. - -## Contact Microsoft to enable the App Key Vault feature +### Contact Microsoft to enable the App Key Vault feature Send an email to TODO@microsoft.com to start the onboarding process. This should be done before you publish your updated extension to Partner Center. @@ -303,7 +301,7 @@ The onboarding process involves a manual verification step that verifies that yo Keep the following information in mind when you use the App Key Vault feature. -### Use NonDebuggable +### Use NonDebuggable As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. From 16774cb8028761bcfe0593765c1e703ad90e67d6 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 3 Jul 2020 12:41:03 +0200 Subject: [PATCH 052/950] updates --- .../administration/extension-key-vault.md | 56 ++++++++++++------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 246e5bb2d6..48b6c46224 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -96,24 +96,28 @@ Follow the tasks in this section to configure an on-premises installation to use ### Prerequisites -- Configure Azure Active Directory (Azure AD) authentication for authenticating [!INCLUDE[prodshort](../developer/includes/prodshort.md)] users. +- An Azure subscription with an Active Directory tenant. - For more information, see [Authenticating Users with Azure Active Directory](authenticating-users-with-azure-active-directory.md). + You sign up for an Azure subscription at [https://azure.microsoft.com](https://azure.microsoft.com). For information about getting an Azure AD tenant, see [How to get an Azure Active Directory tenant](/azure/active-directory/develop/active-directory-howto-tenant). -- Obtain a security certificate +- A security certificate - As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. + As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. - - + ``` ### Create the Azure Key Vault with secrets @@ -131,21 +135,20 @@ Now, you create one or more key vaults in Azure, and add the secrets that you wa There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. -The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](/azure/key-vault/secrets/quick-create-portal). +The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal). For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). ### Register a key vault reader application in Azure AD -Next, register a new application on your Azure AD tenant for reading secrets from the key vaults. - -When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. +Next, register an application on your Azure AD tenant for reading secrets from the key vaults. When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. You can use an existing application if you have one. The steps in this task are done from the the [Azure portal](https://portal.azure.com). -1. Register an Azure AD application for the reading key vault. +1. Sign-in to Azure portal at [portal.azure.com](http://portal.azure.com) and set the portal to your Azure Active Directory tenant. +2. Register an Azure AD application for the reading key vault. - You add the new application by using the [Azure portal](https://portal.azure.com). For guidelines, see [Register your application with your Azure Active Directory tenant](/azure/active-directory/active-directory-app-registration). + You add the new application by using the [Azure portal](https://portal.azure.com). For guidelines, see [Register your application with your Azure Active Directory tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app). When you add an application to an Azure AD tenant, you must specify the following information: @@ -171,13 +174,16 @@ The steps in this task are done from the the [Azure portal](https://portal.azure ### Grant the key vault reader application permission to key vaults -In this task, you grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). +In this task, you grant the key vault reader application permission to read secrets from your key vaults. + +The steps in this task are done from the the [Azure portal](https://portal.azure.com). 1. Open the key vault in the portal. 2. Select **Access policies**, then **Add Access Policy**. 3. Set **Secret Permissions** to **Get**. 4. Select **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. -5. Select **Add**, then **Save**. +5. Select **Add**. +6. Select **Save**. At this point, the work in Azure is finished. @@ -195,9 +201,21 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My ``` - 2. Make a note of the certificate thumbprint because you'll need it in the next step. For instructions on getting the thumbprint using the MMC snap-in, see [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). +2. Give the service account used by the [!INCLUDE[server](../developer/includes/server.md) instance permission to access the certificates private key. + + 1. In the left pane of MMC, expand the **Certificates \(Local Computer\)** node, expand the **Personal** node, and then select the **Certificates** subfolder. + + 2. In the right pane, right-click the certificate, select **All Tasks**, and then choose **Manage Private Keys**. + + 3. In the **Permissions** dialog box for the certificate, choose **Add**. + + 4. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], and then choose the **OK** button. + + 5. In the **Full Control** field, select **Allow**, and then choose the **OK** button. + +3. Make a note of the certificate thumbprint because you'll need it in the next step. For instructions on getting the thumbprint using the MMC snap-in, see [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). -2. Configure the server instance. +4. Configure the server instance. Now, you'll configure App Key Vault settings on the server instance. You can use any of the following methods: From 2d63723532c972d7f961103cc9f5d4ec6ef33402 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 3 Jul 2020 13:52:51 +0200 Subject: [PATCH 053/950] Update extension-key-vault.md --- dev-itpro/administration/extension-key-vault.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 48b6c46224..ff421da2e3 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -295,7 +295,7 @@ To provision the key vault reader application, use the [Azure Active Directory P New-AzureADServicePrincipal -AppId 7e97dcfb-bcdd-426e-8f0a-96439602627a ``` - 7e97dcfb-bcdd-426e-8f0a-96439602627a is the Application (client) ID of Microsoft's centralized Azure AD application. + `7e97dcfb-bcdd-426e-8f0a-96439602627a` is the Application (client) ID of Microsoft's centralized Azure AD application. This step provisions the application in your Azure AD tenant, where it now "lives" together with your key vaults. @@ -343,6 +343,7 @@ Publish-NavApp … -PublisherAzureActiveDirectoryTenantId In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. + ## See Also [Authentication and Credential Types](Users-Credential-Types.md) From 3bcb1df091369342aab3f1ae69550142c68325db Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 3 Jul 2020 14:46:08 +0200 Subject: [PATCH 054/950] Update telemetry-extension-key-vault-trace.md --- .../telemetry-extension-key-vault-trace.md | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md index d0970d4bba..56522ebd08 100644 --- a/dev-itpro/administration/telemetry-extension-key-vault-trace.md +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -17,8 +17,23 @@ ms.author: jswymer App key vault telemetry gathers information about the acquisition of secrets in Azure Key Vaults by extensions at runtime. Extensions can be configured to retrieve secrets from one or key vaults. -There are various reasons retrieving secret might fail, for example, -The gathered data can help you identify, troubleshoot, and resolve issues with per-tenant extensions. For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). +The app key vault secret process has two operations: *initialization* and *retrieval*. The telemetry data provides information about the success or failure for each of these operations. There are various conditions that cause a failure. The failure messages provide insight into the cause of the failure, helping you identify, troubleshoot, and resolve issues. + +- Initialization is the first stage. This stage verifies the configuration of the app key vault provider in the extension and on the service. To give you a better understanding idea of what happens in this stage, here are some conditions that cause failures: + + - The extension doesn't specify a key vault in it's app.json file. + - The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. + - The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. + +- Retrieval is the second stage, and occurs after a successful initialization. In this stage, the service tries to get a secret from a specified key vault. Some conditions that cause failures include: + + - The secret name requested by the extension is missing or not valid. + - + - The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. + - The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. + + +For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). ## App Key Vault secret initialization succeeded @@ -48,10 +63,10 @@ Occurs when an extension secret was successfully initialized. |environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| |environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| |eventId|**RT0014**| -|extensionName|Specifies the name of the extension.| -|extensionId|Specifies the AppID of the extension.| -|extensionPublisher|Specifies the publisher of the extension| -|extensionVersion|Specifies the version of the extension.| +|extensionName|Specifies the name of the extension that requested the secret. | +|extensionId|Specifies the AppID of the extension that requested the secret.| +|extensionPublisher|Specifies the publisher of the extension that requested the secret. | +|extensionVersion|Specifies the version of the extension that requested the secret.| |keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| |telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| @@ -89,10 +104,9 @@ Occurs when a key vault failed to be initialized. |environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| |environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| |eventId|**RT0015**| -|extensionName|Specifies the name of the extension.| -|extensionId|Specifies the AppID of the extension.| -|extensionPublisher|Specifies the publisher of the extension| -|extensionVersion|Specifies the version of the extension.| +|extensionId|Specifies the AppID of the extension that requested the secret.| +|extensionPublisher|Specifies the publisher of the extension that requested the secret. | +|extensionVersion|Specifies the version of the extension that requested the secret.| |failureReason|Specifies the error that occurred.| |telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| @@ -100,7 +114,7 @@ Occurs when a key vault failed to be initialized. ## App Key Vault secret retrieval succeeded @@ -131,10 +145,9 @@ Occurs when a secret used by an extension is successfully retrieved from an Azur |environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| |environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| |eventId|**RT0016**| -|extensionName|Specifies the name of the extension.| -|extensionId|Specifies the AppID of the extension.| -|extensionPublisher|Specifies the publisher of the extension| -|extensionVersion|Specifies the version of the extension.| +|extensionId|Specifies the AppID of the extension that requested the secret.| +|extensionPublisher|Specifies the publisher of the extension that requested the secret. | +|extensionVersion|Specifies the version of the extension that requested the secret.| |keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| |telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| @@ -170,11 +183,9 @@ Occurs when an extension failed to retrieve a secret from a specified Azure key |environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| |environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| |eventId|**RT0017**| -|extensionName|Specifies the name of the extension.| -|extensionId|Specifies the AppID of the extension.| -|extensionPublisher|Specifies the publisher of the extension| -|extensionVersion|Specifies the version of the extension.| -|failureReason|Specifies the error that occurred.| +|extensionId|Specifies the AppID of the extension that requested the secret.| +|extensionPublisher|Specifies the publisher of the extension that requested the secret. | +|extensionVersion|Specifies the version of the extension that requested the secret.| |keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| |telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| @@ -189,7 +200,7 @@ Occurs when an extension failed to retrieve a secret from a specified Azure key ## See also -[Upgrading Extensions](../developer/devenv-upgrading-extensions.md) +[App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md) [Monitoring and Analyzing Telemetry](telemetry-overview.md) [Enabling Application Insights for Tenant Telemetry On-Premises](telemetry-enable-application-insights.md) [Enable Sending Telemetry to Application Insights](tenant-admin-center-telemetry.md#appinsights) From 4253ff98dfb9d7a48577d6d291f5d5ef759e7a1d Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 3 Jul 2020 14:55:35 +0200 Subject: [PATCH 055/950] Update telemetry-extension-key-vault-trace.md --- .../telemetry-extension-key-vault-trace.md | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md index 56522ebd08..939e21555f 100644 --- a/dev-itpro/administration/telemetry-extension-key-vault-trace.md +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -19,19 +19,21 @@ App key vault telemetry gathers information about the acquisition of secrets in The app key vault secret process has two operations: *initialization* and *retrieval*. The telemetry data provides information about the success or failure for each of these operations. There are various conditions that cause a failure. The failure messages provide insight into the cause of the failure, helping you identify, troubleshoot, and resolve issues. -- Initialization is the first stage. This stage verifies the configuration of the app key vault provider in the extension and on the service. To give you a better understanding idea of what happens in this stage, here are some conditions that cause failures: +#### Initialization - - The extension doesn't specify a key vault in it's app.json file. - - The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. - - The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. +Initialization is the first stage. This stage verifies the configuration of the app key vault provider in the extension and on the service. To give you a better understanding idea of what happens in this stage, here are some conditions that cause failures: -- Retrieval is the second stage, and occurs after a successful initialization. In this stage, the service tries to get a secret from a specified key vault. Some conditions that cause failures include: +- The extension doesn't specify a key vault in it's app.json file. +- The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. +- The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. - - The secret name requested by the extension is missing or not valid. - - - - The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. - - The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. +#### Retrieval +Retrieval is the second stage, and occurs after a successful initialization. In this stage, the service tries to get a secret from a specified key vault. Some conditions that cause failures include: + +- The secret name requested by the extension is missing or not valid. +- The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. +- The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). From 4016f11686fe6684b74bb73c8efd26fbb63627d1 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 3 Jul 2020 16:06:49 +0200 Subject: [PATCH 056/950] Update extension-key-vault.md --- .../administration/extension-key-vault.md | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index ff421da2e3..5a0ccb744f 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -102,13 +102,12 @@ Follow the tasks in this section to configure an on-premises installation to use - A security certificate - As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. + As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used to prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. For example, on your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer, start Windows PowerShell as an administrator. Then at the prompt, run the following commands, one at a time: ```powershell $cert = New-SelfSignedCertificate -Subject "BusinessCentralKeyVaultReader" -Provider "Microsoft Strong Cryptographic Provider" - Export-Certificate -Cert $cert -FilePath c:\certs\BusinessCentralKeyVaultReader.cer ``` ```powershell @@ -119,6 +118,8 @@ Follow the tasks in this section to configure an on-premises installation to use Export-Certificate -Cert $cert -FilePath c:\certs\BusinessCentralKeyVaultReader.cer ``` + These commands add a certificate called BusinessCentralKeyVaultReader to the computer's **LocalMachine** > **Personal (My)** certificate store. + ### Create the Azure Key Vault with secrets Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. @@ -193,7 +194,7 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) 1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md) server computer. - 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) orr [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. + 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. For example, the following PowerShell command installs a certificate to the local machine's personal store: @@ -203,31 +204,27 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) 2. Give the service account used by the [!INCLUDE[server](../developer/includes/server.md) instance permission to access the certificates private key. - 1. In the left pane of MMC, expand the **Certificates \(Local Computer\)** node, expand the **Personal** node, and then select the **Certificates** subfolder. + To do this using the MMC: + + 1. Open the MMC snap-in for certificates. See [How to: View Certificates with the MMC Snap-in](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in). + + 2. Expand the **Certificates \(Local Computer\)** node, expand the **Personal** node, and then select the **Certificates** subfolder. - 2. In the right pane, right-click the certificate, select **All Tasks**, and then choose **Manage Private Keys**. + 3. In the right pane, right-click the certificate, select **All Tasks**, and then choose **Manage Private Keys**. - 3. In the **Permissions** dialog box for the certificate, choose **Add**. + 4. In the **Permissions** dialog box for the certificate, choose **Add**. - 4. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], and then choose the **OK** button. + 5. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], and then choose the **OK** button. - 5. In the **Full Control** field, select **Allow**, and then choose the **OK** button. + 6. In the **Full Control** field, select **Allow**, and then choose the **OK** button. -3. Make a note of the certificate thumbprint because you'll need it in the next step. For instructions on getting the thumbprint using the MMC snap-in, see [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). +3. Make a note of the certificate thumbprint because you'll need it in the next step. See [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). -4. Configure the server instance. +4. Configure the [!INCLUDE[server](../developer/includes/server.md) instance. - Now, you'll configure App Key Vault settings on the server instance. You can use any of the following methods: - - - [!INCLUDE[admintool](../developer/includes/admintool.md) - - [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration) of the [!INCLUDE[adminshell](../developer/includes/adminshell.md). - - Manually modifying the server instances CustomSetting.config file. - - For more information about using these tools, see [Configuring Business Central Server](configure-server-instance.md). - - The following table describes the settings that you configure to enable Azure key vault on the server instance: + Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure to enable Azure key vault on the server instance: - |Setting|Key name in CustomSetting.config|Value|Example| + |Admin Tool Setting|Key name for CustomSetting.config|Value|Example| |--------|-------------------------------|-----|-------| |Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Set to the certificate store location where key vault certificate was stored.|LocalMachine| |Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Set to the certificate store name where key vault certificate was stored.|MY| @@ -235,6 +232,20 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) |Client ID|AzureKeyVaultClientId|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| |Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| + You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). + + For example, to use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Substitute brackets with your own values. + + ```powershell + Import-Module Microsoft.Dynamics.Nav.Management.dll + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreLocation -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreName -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateThumbprint -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientId -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultAppSecretsPublisherValidationEnabled -KeyValue false + Restart-NAVServerInstance -ServerInstance + ``` + > [!IMPORTANT] > Setting the `AzureKeyVaultAppSecretsPublisherValidationEnabled` to false means the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. @@ -347,4 +358,5 @@ In SaaS, this value will always be empty for PTEs and dev extensions, and it wil ## See Also [Authentication and Credential Types](Users-Credential-Types.md) -[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) \ No newline at end of file +[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) +[Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file From 29a7ea8db857aad6e1f466ca2504ca660d8b8c2c Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 3 Jul 2020 17:42:27 +0200 Subject: [PATCH 057/950] fix --- .../administration/extension-key-vault.md | 8 +- .../setup-app-key-vault-onprem.md | 362 ++++++++++++++++++ .../administration/setup-app-key-vault.md | 362 ++++++++++++++++++ 3 files changed, 728 insertions(+), 4 deletions(-) create mode 100644 dev-itpro/administration/setup-app-key-vault-onprem.md create mode 100644 dev-itpro/administration/setup-app-key-vault.md diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 5a0ccb744f..a8a731cc0e 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -12,9 +12,9 @@ author: jswymer --- # App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions -Some [!INCLUDE[prodshort](../developer/includes/prodshort.md) extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md) services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. +Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. -These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md) extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. +These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. The credential is a kind of secret. It is secret to the extension. It shouldn't leak to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. @@ -190,9 +190,9 @@ At this point, the work in Azure is finished. ### Configure the Business Central Server for the Apps Key Vault -Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. +Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. -1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md) server computer. +1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md new file mode 100644 index 0000000000..a8a731cc0e --- /dev/null +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -0,0 +1,362 @@ +--- +title: Azure Key Vaults with Business Central +description: Describes how to use an Azure Key vault with Business Central extensions. +ms.custom: na +ms.date: 04/01/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: jswymer +--- +# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions + +Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. + +These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. + +The credential is a kind of secret. It is secret to the extension. It shouldn't leak to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. + +Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. + +## Specifying Azure Key Vault in extensions + +To use an Azure Key Vault for an extension, you specify the key vault the extension's manifest file (app.json), like this: + +``` + + +    "keyVaultUrls": [ + +        "https://mykeyvault.vault.azure.net" + +    ] + +``` + +Then, you can add code to the extension to read secrets from the key vault at runtime, like this: + +``` +page 50100 HelloWorldPage + +{ + +    var + +        SecretProvider: Codeunit "App Key Vault Secret Provider"; + +        SecretValue: Text; + +    trigger OnOpenPage(); + +    begin + +        if SecretProvider.TryInitializeFromCurrentApp() then begin + +            SecretProvider.GetSecret('secret1', SecretValue); + +            Message('retrieved secret: ' + SecretValue); + +        end + +        else + +            Message('ERROR: ' + GetLastErrorText()); + +    end; + +} + +``` + +The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. + + +## Specifying two Azure Key Vaults + +An extension manifest can specify up to two Azure Key Vaults, like this: + +``` + +    "keyVaultUrls": [ + +        "https://myfirstkeyvault.vault.azure.net", + +        "https://mysecondkeyvault.vault.azure.net" + +    ] +``` + +The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. + +## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises + +Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. + +### Prerequisites + +- An Azure subscription with an Active Directory tenant. + + You sign up for an Azure subscription at [https://azure.microsoft.com](https://azure.microsoft.com). For information about getting an Azure AD tenant, see [How to get an Azure Active Directory tenant](/azure/active-directory/develop/active-directory-howto-tenant). + +- A security certificate + + As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used to prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. + + In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. For example, on your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer, start Windows PowerShell as an administrator. Then at the prompt, run the following commands, one at a time: + + ```powershell + $cert = New-SelfSignedCertificate -Subject "BusinessCentralKeyVaultReader" -Provider "Microsoft Strong Cryptographic Provider" + ``` + + ```powershell + $cert.Thumbprint + ``` + + ```powershell + Export-Certificate -Cert $cert -FilePath c:\certs\BusinessCentralKeyVaultReader.cer + ``` + + These commands add a certificate called BusinessCentralKeyVaultReader to the computer's **LocalMachine** > **Personal (My)** certificate store. + +### Create the Azure Key Vault with secrets + +Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. + + + +There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. + +The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal). + +For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). + +### Register a key vault reader application in Azure AD + +Next, register an application on your Azure AD tenant for reading secrets from the key vaults. When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. You can use an existing application if you have one. + +The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Sign-in to Azure portal at [portal.azure.com](http://portal.azure.com) and set the portal to your Azure Active Directory tenant. +2. Register an Azure AD application for the reading key vault. + + You add the new application by using the [Azure portal](https://portal.azure.com). For guidelines, see [Register your application with your Azure Active Directory tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app). + + When you add an application to an Azure AD tenant, you must specify the following information: + + |Setting|Description| + |-------|-----------| + |Name|The name of your application as it will display to your users, such as *Business Central Key Vault Reader*.| + |Supported account types|Specifies which accounts that you would like your application to support. For purposes of this article, select **Accounts in this organizational directory only**. | + + + When completed, the **Overview** displays in the portal for the new application. + + Make a note of the **Display name** and/or **Application (client) ID**. You will use this information later. + +2. Upload the security certificate to the registered application. + + In this step, you upload the certificate file that you obtained as part of the prerequisites. + + From the key vault reader application overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions to locate and upload the certificate. + +### Grant the key vault reader application permission to key vaults + +In this task, you grant the key vault reader application permission to read secrets from your key vaults. + +The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Open the key vault in the portal. +2. Select **Access policies**, then **Add Access Policy**. +3. Set **Secret Permissions** to **Get**. +4. Select **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. +5. Select **Add**. +6. Select **Save**. + +At this point, the work in Azure is finished. + +### Configure the Business Central Server for the Apps Key Vault + +Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. + +1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. + + 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. + + For example, the following PowerShell command installs a certificate to the local machine's personal store: + + ```powershell + Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My + ``` + +2. Give the service account used by the [!INCLUDE[server](../developer/includes/server.md) instance permission to access the certificates private key. + + To do this using the MMC: + + 1. Open the MMC snap-in for certificates. See [How to: View Certificates with the MMC Snap-in](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in). + + 2. Expand the **Certificates \(Local Computer\)** node, expand the **Personal** node, and then select the **Certificates** subfolder. + + 3. In the right pane, right-click the certificate, select **All Tasks**, and then choose **Manage Private Keys**. + + 4. In the **Permissions** dialog box for the certificate, choose **Add**. + + 5. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], and then choose the **OK** button. + + 6. In the **Full Control** field, select **Allow**, and then choose the **OK** button. + +3. Make a note of the certificate thumbprint because you'll need it in the next step. See [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). + +4. Configure the [!INCLUDE[server](../developer/includes/server.md) instance. + + Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure to enable Azure key vault on the server instance: + + |Admin Tool Setting|Key name for CustomSetting.config|Value|Example| + |--------|-------------------------------|-----|-------| + |Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Set to the certificate store location where key vault certificate was stored.|LocalMachine| + |Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Set to the certificate store name where key vault certificate was stored.|MY| + |Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| + |Client ID|AzureKeyVaultClientId|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| + |Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| + + You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). + + For example, to use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Substitute brackets with your own values. + + ```powershell + Import-Module Microsoft.Dynamics.Nav.Management.dll + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreLocation -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreName -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateThumbprint -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientId -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultAppSecretsPublisherValidationEnabled -KeyValue false + Restart-NAVServerInstance -ServerInstance + ``` + + > [!IMPORTANT] + > Setting the `AzureKeyVaultAppSecretsPublisherValidationEnabled` to false means the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. + +At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. + +## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online + +In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. + +### Create the Azure Key Vault with secrets + +Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. + + +There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. + +The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](/azure/key-vault/secrets/quick-create-portal). + +For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). + +### Provision the key reader application in your Azure AD tenant + +Your Business Central online solution is configured to use an Azure AD application for reading key vault secrets. The application is called **Dynamics 365 Business Central ISV Key Vault Reader**. Microsoft manages the key vault reader application, however, there are a couple tasks that you have to do to enable it. First, the application must be provisioned on your Azure AD tenant, as described here. + +To provision the key vault reader application, use the [Azure Active Directory PowerShell module](/powershell/module/azuread). + +1. Open Windows PowerShell as an administrator. +2. Install the Azure Active Directory PowerShell module. + + ```powershell + Install-Module AzureAD + ``` +3. Import the Azure AD module. + + ```powershell + Import-Module AzureAD + ``` +4. Connect to your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Azure AD tenant. + + 1. Run the following command: + + ```powershell + Connect-AzureAD + ``` + 2. Provide your sign-in name and password when prompted. + +4. Create an Azure AD service principal using the following command: + + ```powershell + New-AzureADServicePrincipal -AppId 7e97dcfb-bcdd-426e-8f0a-96439602627a + ``` + + `7e97dcfb-bcdd-426e-8f0a-96439602627a` is the Application (client) ID of Microsoft's centralized Azure AD application. + + This step provisions the application in your Azure AD tenant, where it now "lives" together with your key vaults. + +### Grant the key vault reader application permission to your key vaults + +The next task is to grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Open the key vault in the portal. +2. Select **Access policies**, then **Add Access Policy**. +3. Set **Secret Permissions** to **Get**. +4. Select **Select principal**, and on the right, search for either the application (client) ID **7e97dcfb-bcdd-426e-8f0a-96439602627a** or the display name **Dynamics 365 Business Central ISV Key Vault Reader**. +5. Select **Add**, then **Save**. + +### Contact Microsoft to enable the App Key Vault feature + +Send an email to TODO@microsoft.com to start the onboarding process. This should be done before you publish your updated extension to Partner Center. + +The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. + +## Security considerations + +Keep the following information in mind when you use the App Key Vault feature. + +### Use NonDebuggable + +As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. + +### Don't pass the App Key Vault Secret Provider to untrusted code + +Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. + +### Run with publisher validation + +In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. + +When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: + +`Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId` + +Only if this check is satisfied will the initialization succeed. + +So how does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: + +Publish-NavApp … -PublisherAzureActiveDirectoryTenantId + +In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. + + +## See Also + +[Authentication and Credential Types](Users-Credential-Types.md) +[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) +[Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file diff --git a/dev-itpro/administration/setup-app-key-vault.md b/dev-itpro/administration/setup-app-key-vault.md new file mode 100644 index 0000000000..a8a731cc0e --- /dev/null +++ b/dev-itpro/administration/setup-app-key-vault.md @@ -0,0 +1,362 @@ +--- +title: Azure Key Vaults with Business Central +description: Describes how to use an Azure Key vault with Business Central extensions. +ms.custom: na +ms.date: 04/01/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: jswymer +--- +# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions + +Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. + +These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. + +The credential is a kind of secret. It is secret to the extension. It shouldn't leak to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. + +Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. + +## Specifying Azure Key Vault in extensions + +To use an Azure Key Vault for an extension, you specify the key vault the extension's manifest file (app.json), like this: + +``` + + +    "keyVaultUrls": [ + +        "https://mykeyvault.vault.azure.net" + +    ] + +``` + +Then, you can add code to the extension to read secrets from the key vault at runtime, like this: + +``` +page 50100 HelloWorldPage + +{ + +    var + +        SecretProvider: Codeunit "App Key Vault Secret Provider"; + +        SecretValue: Text; + +    trigger OnOpenPage(); + +    begin + +        if SecretProvider.TryInitializeFromCurrentApp() then begin + +            SecretProvider.GetSecret('secret1', SecretValue); + +            Message('retrieved secret: ' + SecretValue); + +        end + +        else + +            Message('ERROR: ' + GetLastErrorText()); + +    end; + +} + +``` + +The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. + + +## Specifying two Azure Key Vaults + +An extension manifest can specify up to two Azure Key Vaults, like this: + +``` + +    "keyVaultUrls": [ + +        "https://myfirstkeyvault.vault.azure.net", + +        "https://mysecondkeyvault.vault.azure.net" + +    ] +``` + +The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. + +## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises + +Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. + +### Prerequisites + +- An Azure subscription with an Active Directory tenant. + + You sign up for an Azure subscription at [https://azure.microsoft.com](https://azure.microsoft.com). For information about getting an Azure AD tenant, see [How to get an Azure Active Directory tenant](/azure/active-directory/develop/active-directory-howto-tenant). + +- A security certificate + + As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used to prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. + + In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. For example, on your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer, start Windows PowerShell as an administrator. Then at the prompt, run the following commands, one at a time: + + ```powershell + $cert = New-SelfSignedCertificate -Subject "BusinessCentralKeyVaultReader" -Provider "Microsoft Strong Cryptographic Provider" + ``` + + ```powershell + $cert.Thumbprint + ``` + + ```powershell + Export-Certificate -Cert $cert -FilePath c:\certs\BusinessCentralKeyVaultReader.cer + ``` + + These commands add a certificate called BusinessCentralKeyVaultReader to the computer's **LocalMachine** > **Personal (My)** certificate store. + +### Create the Azure Key Vault with secrets + +Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. + + + +There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. + +The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal). + +For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). + +### Register a key vault reader application in Azure AD + +Next, register an application on your Azure AD tenant for reading secrets from the key vaults. When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. You can use an existing application if you have one. + +The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Sign-in to Azure portal at [portal.azure.com](http://portal.azure.com) and set the portal to your Azure Active Directory tenant. +2. Register an Azure AD application for the reading key vault. + + You add the new application by using the [Azure portal](https://portal.azure.com). For guidelines, see [Register your application with your Azure Active Directory tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app). + + When you add an application to an Azure AD tenant, you must specify the following information: + + |Setting|Description| + |-------|-----------| + |Name|The name of your application as it will display to your users, such as *Business Central Key Vault Reader*.| + |Supported account types|Specifies which accounts that you would like your application to support. For purposes of this article, select **Accounts in this organizational directory only**. | + + + When completed, the **Overview** displays in the portal for the new application. + + Make a note of the **Display name** and/or **Application (client) ID**. You will use this information later. + +2. Upload the security certificate to the registered application. + + In this step, you upload the certificate file that you obtained as part of the prerequisites. + + From the key vault reader application overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions to locate and upload the certificate. + +### Grant the key vault reader application permission to key vaults + +In this task, you grant the key vault reader application permission to read secrets from your key vaults. + +The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Open the key vault in the portal. +2. Select **Access policies**, then **Add Access Policy**. +3. Set **Secret Permissions** to **Get**. +4. Select **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. +5. Select **Add**. +6. Select **Save**. + +At this point, the work in Azure is finished. + +### Configure the Business Central Server for the Apps Key Vault + +Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. + +1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. + + 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. + + For example, the following PowerShell command installs a certificate to the local machine's personal store: + + ```powershell + Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My + ``` + +2. Give the service account used by the [!INCLUDE[server](../developer/includes/server.md) instance permission to access the certificates private key. + + To do this using the MMC: + + 1. Open the MMC snap-in for certificates. See [How to: View Certificates with the MMC Snap-in](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in). + + 2. Expand the **Certificates \(Local Computer\)** node, expand the **Personal** node, and then select the **Certificates** subfolder. + + 3. In the right pane, right-click the certificate, select **All Tasks**, and then choose **Manage Private Keys**. + + 4. In the **Permissions** dialog box for the certificate, choose **Add**. + + 5. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], and then choose the **OK** button. + + 6. In the **Full Control** field, select **Allow**, and then choose the **OK** button. + +3. Make a note of the certificate thumbprint because you'll need it in the next step. See [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). + +4. Configure the [!INCLUDE[server](../developer/includes/server.md) instance. + + Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure to enable Azure key vault on the server instance: + + |Admin Tool Setting|Key name for CustomSetting.config|Value|Example| + |--------|-------------------------------|-----|-------| + |Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Set to the certificate store location where key vault certificate was stored.|LocalMachine| + |Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Set to the certificate store name where key vault certificate was stored.|MY| + |Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| + |Client ID|AzureKeyVaultClientId|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| + |Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| + + You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). + + For example, to use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Substitute brackets with your own values. + + ```powershell + Import-Module Microsoft.Dynamics.Nav.Management.dll + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreLocation -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreName -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateThumbprint -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientId -KeyValue + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultAppSecretsPublisherValidationEnabled -KeyValue false + Restart-NAVServerInstance -ServerInstance + ``` + + > [!IMPORTANT] + > Setting the `AzureKeyVaultAppSecretsPublisherValidationEnabled` to false means the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. + +At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. + +## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online + +In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. + +### Create the Azure Key Vault with secrets + +Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. + + +There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. + +The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](/azure/key-vault/secrets/quick-create-portal). + +For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). + +### Provision the key reader application in your Azure AD tenant + +Your Business Central online solution is configured to use an Azure AD application for reading key vault secrets. The application is called **Dynamics 365 Business Central ISV Key Vault Reader**. Microsoft manages the key vault reader application, however, there are a couple tasks that you have to do to enable it. First, the application must be provisioned on your Azure AD tenant, as described here. + +To provision the key vault reader application, use the [Azure Active Directory PowerShell module](/powershell/module/azuread). + +1. Open Windows PowerShell as an administrator. +2. Install the Azure Active Directory PowerShell module. + + ```powershell + Install-Module AzureAD + ``` +3. Import the Azure AD module. + + ```powershell + Import-Module AzureAD + ``` +4. Connect to your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Azure AD tenant. + + 1. Run the following command: + + ```powershell + Connect-AzureAD + ``` + 2. Provide your sign-in name and password when prompted. + +4. Create an Azure AD service principal using the following command: + + ```powershell + New-AzureADServicePrincipal -AppId 7e97dcfb-bcdd-426e-8f0a-96439602627a + ``` + + `7e97dcfb-bcdd-426e-8f0a-96439602627a` is the Application (client) ID of Microsoft's centralized Azure AD application. + + This step provisions the application in your Azure AD tenant, where it now "lives" together with your key vaults. + +### Grant the key vault reader application permission to your key vaults + +The next task is to grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). + +1. Open the key vault in the portal. +2. Select **Access policies**, then **Add Access Policy**. +3. Set **Secret Permissions** to **Get**. +4. Select **Select principal**, and on the right, search for either the application (client) ID **7e97dcfb-bcdd-426e-8f0a-96439602627a** or the display name **Dynamics 365 Business Central ISV Key Vault Reader**. +5. Select **Add**, then **Save**. + +### Contact Microsoft to enable the App Key Vault feature + +Send an email to TODO@microsoft.com to start the onboarding process. This should be done before you publish your updated extension to Partner Center. + +The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. + +## Security considerations + +Keep the following information in mind when you use the App Key Vault feature. + +### Use NonDebuggable + +As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. + +### Don't pass the App Key Vault Secret Provider to untrusted code + +Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. + +### Run with publisher validation + +In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. + +When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: + +`Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId` + +Only if this check is satisfied will the initialization succeed. + +So how does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: + +Publish-NavApp … -PublisherAzureActiveDirectoryTenantId + +In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. + + +## See Also + +[Authentication and Credential Types](Users-Credential-Types.md) +[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) +[Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file From 1dbb171cf522d8276b6cc4fad6c904be52f94ead Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 3 Jul 2020 20:19:15 +0200 Subject: [PATCH 058/950] Update setup-app-key-vault-onprem.md --- .../setup-app-key-vault-onprem.md | 144 ------------------ 1 file changed, 144 deletions(-) diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index a8a731cc0e..98719c4252 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -20,76 +20,6 @@ The credential is a kind of secret. It is secret to the extension. It shouldn't Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. -## Specifying Azure Key Vault in extensions - -To use an Azure Key Vault for an extension, you specify the key vault the extension's manifest file (app.json), like this: - -``` - - -    "keyVaultUrls": [ - -        "https://mykeyvault.vault.azure.net" - -    ] - -``` - -Then, you can add code to the extension to read secrets from the key vault at runtime, like this: - -``` -page 50100 HelloWorldPage - -{ - -    var - -        SecretProvider: Codeunit "App Key Vault Secret Provider"; - -        SecretValue: Text; - -    trigger OnOpenPage(); - -    begin - -        if SecretProvider.TryInitializeFromCurrentApp() then begin - -            SecretProvider.GetSecret('secret1', SecretValue); - -            Message('retrieved secret: ' + SecretValue); - -        end - -        else - -            Message('ERROR: ' + GetLastErrorText()); - -    end; - -} - -``` - -The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. - - -## Specifying two Azure Key Vaults - -An extension manifest can specify up to two Azure Key Vaults, like this: - -``` - -    "keyVaultUrls": [ - -        "https://myfirstkeyvault.vault.azure.net", - -        "https://mysecondkeyvault.vault.azure.net" - -    ] -``` - -The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. - ## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. @@ -251,80 +181,6 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. -## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online - -In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. - -### Create the Azure Key Vault with secrets - -Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. - - -There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. - -The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](/azure/key-vault/secrets/quick-create-portal). - -For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). - -### Provision the key reader application in your Azure AD tenant - -Your Business Central online solution is configured to use an Azure AD application for reading key vault secrets. The application is called **Dynamics 365 Business Central ISV Key Vault Reader**. Microsoft manages the key vault reader application, however, there are a couple tasks that you have to do to enable it. First, the application must be provisioned on your Azure AD tenant, as described here. - -To provision the key vault reader application, use the [Azure Active Directory PowerShell module](/powershell/module/azuread). - -1. Open Windows PowerShell as an administrator. -2. Install the Azure Active Directory PowerShell module. - - ```powershell - Install-Module AzureAD - ``` -3. Import the Azure AD module. - - ```powershell - Import-Module AzureAD - ``` -4. Connect to your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Azure AD tenant. - - 1. Run the following command: - - ```powershell - Connect-AzureAD - ``` - 2. Provide your sign-in name and password when prompted. - -4. Create an Azure AD service principal using the following command: - - ```powershell - New-AzureADServicePrincipal -AppId 7e97dcfb-bcdd-426e-8f0a-96439602627a - ``` - - `7e97dcfb-bcdd-426e-8f0a-96439602627a` is the Application (client) ID of Microsoft's centralized Azure AD application. - - This step provisions the application in your Azure AD tenant, where it now "lives" together with your key vaults. - -### Grant the key vault reader application permission to your key vaults - -The next task is to grant the key vault reader application permission to read secrets from your key vaults. The steps in this task are done from the the [Azure portal](https://portal.azure.com). - -1. Open the key vault in the portal. -2. Select **Access policies**, then **Add Access Policy**. -3. Set **Secret Permissions** to **Get**. -4. Select **Select principal**, and on the right, search for either the application (client) ID **7e97dcfb-bcdd-426e-8f0a-96439602627a** or the display name **Dynamics 365 Business Central ISV Key Vault Reader**. -5. Select **Add**, then **Save**. - -### Contact Microsoft to enable the App Key Vault feature - -Send an email to TODO@microsoft.com to start the onboarding process. This should be done before you publish your updated extension to Partner Center. - -The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. ## Security considerations From f4fb94610324ee41bdfdca301275c12f0f6801df Mon Sep 17 00:00:00 2001 From: jswymer Date: Mon, 6 Jul 2020 08:22:36 +0200 Subject: [PATCH 059/950] fix --- .../administration/extension-key-vault.md | 15 +- .../setup-app-key-vault-onprem.md | 64 +--- .../administration/setup-app-key-vault.md | 284 +----------------- 3 files changed, 32 insertions(+), 331 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index a8a731cc0e..48250ebe65 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -10,14 +10,25 @@ ms.topic: article ms.service: "dynamics365-business-central" author: jswymer --- -# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions +# Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. -The credential is a kind of secret. It is secret to the extension. It shouldn't leak to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. +Consider the credential as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. +## Getting started + +There are two parts to using secrets with extensions. + +- One or more key vaults for storing secrets must be set up in Azure, and [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service must be configured to access the key vaults. + + The setup is different for online and on-premises. For more information, see: + - [](setup-app-key-vault.md) + - [](setup-app-key-vault-onprem.md) + +- Extensions must be developed with code that specifies the key vaults Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. ## Specifying Azure Key Vault in extensions diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index 98719c4252..87ba9e0697 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -10,21 +10,11 @@ ms.topic: article ms.service: "dynamics365-business-central" author: jswymer --- -# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions - -Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. - -These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. - -The credential is a kind of secret. It is secret to the extension. It shouldn't leak to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. - -Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. - -## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises +# Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. -### Prerequisites +## Prerequisites - An Azure subscription with an Active Directory tenant. @@ -50,7 +40,7 @@ Follow the tasks in this section to configure an on-premises installation to use These commands add a certificate called BusinessCentralKeyVaultReader to the computer's **LocalMachine** > **Personal (My)** certificate store. -### Create the Azure Key Vault with secrets +## Create the Azure Key Vault with secrets Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. @@ -70,7 +60,7 @@ The easiest way is to use the Azure portal. For instructions, see [Quickstart: S For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). -### Register a key vault reader application in Azure AD +## Register a key vault reader application in Azure AD Next, register an application on your Azure AD tenant for reading secrets from the key vaults. When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. You can use an existing application if you have one. @@ -103,7 +93,7 @@ The steps in this task are done from the the [Azure portal](https://portal.azure From the key vault reader application overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions to locate and upload the certificate. -### Grant the key vault reader application permission to key vaults +## Grant the key vault reader application permission to key vaults In this task, you grant the key vault reader application permission to read secrets from your key vaults. @@ -118,7 +108,7 @@ The steps in this task are done from the the [Azure portal](https://portal.azure At this point, the work in Azure is finished. -### Configure the Business Central Server for the Apps Key Vault +## Configure the Business Central Server for the Apps Key Vault Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. @@ -154,13 +144,13 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure to enable Azure key vault on the server instance: - |Admin Tool Setting|Key name for CustomSetting.config|Value|Example| + |Setting
(key name)|Value|Example| |--------|-------------------------------|-----|-------| - |Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Set to the certificate store location where key vault certificate was stored.|LocalMachine| - |Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Set to the certificate store name where key vault certificate was stored.|MY| - |Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| - |Client ID|AzureKeyVaultClientId|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| - |Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| + |Client Certificate Store Location
(AzureKeyVaultClientCertificateStoreLocation)|Set to the certificate store location where key vault certificate was stored.|LocalMachine| + |Client Certificate Store Name
(AzureKeyVaultClientCertificateStoreName)|Set to the certificate store name where key vault certificate was stored.|MY| + |Client Certificate Thumbprint
(AzureKeyVaultClientCertificateThumbprint)|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| + |Client ID
(AzureKeyVaultClientId)|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| + |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). @@ -181,36 +171,6 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. - -## Security considerations - -Keep the following information in mind when you use the App Key Vault feature. - -### Use NonDebuggable - -As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. - -### Don't pass the App Key Vault Secret Provider to untrusted code - -Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. - -### Run with publisher validation - -In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. - -When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: - -`Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId` - -Only if this check is satisfied will the initialization succeed. - -So how does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: - -Publish-NavApp … -PublisherAzureActiveDirectoryTenantId - -In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. - - ## See Also [Authentication and Credential Types](Users-Credential-Types.md) diff --git a/dev-itpro/administration/setup-app-key-vault.md b/dev-itpro/administration/setup-app-key-vault.md index a8a731cc0e..8602a9f31a 100644 --- a/dev-itpro/administration/setup-app-key-vault.md +++ b/dev-itpro/administration/setup-app-key-vault.md @@ -1,6 +1,6 @@ --- -title: Azure Key Vaults with Business Central -description: Describes how to use an Azure Key vault with Business Central extensions. +title: Setting up App Key Vaults for Business Central +description: Describes how to use an Azure Key vault with Business Central extensions for online. ms.custom: na ms.date: 04/01/2020 ms.reviewer: na @@ -10,252 +10,11 @@ ms.topic: article ms.service: "dynamics365-business-central" author: jswymer --- -# App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions - -Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. - -These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. - -The credential is a kind of secret. It is secret to the extension. It shouldn't leak to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. - -Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. - -## Specifying Azure Key Vault in extensions - -To use an Azure Key Vault for an extension, you specify the key vault the extension's manifest file (app.json), like this: - -``` - - -    "keyVaultUrls": [ - -        "https://mykeyvault.vault.azure.net" - -    ] - -``` - -Then, you can add code to the extension to read secrets from the key vault at runtime, like this: - -``` -page 50100 HelloWorldPage - -{ - -    var - -        SecretProvider: Codeunit "App Key Vault Secret Provider"; - -        SecretValue: Text; - -    trigger OnOpenPage(); - -    begin - -        if SecretProvider.TryInitializeFromCurrentApp() then begin - -            SecretProvider.GetSecret('secret1', SecretValue); - -            Message('retrieved secret: ' + SecretValue); - -        end - -        else - -            Message('ERROR: ' + GetLastErrorText()); - -    end; - -} - -``` - -The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. - - -## Specifying two Azure Key Vaults - -An extension manifest can specify up to two Azure Key Vaults, like this: - -``` - -    "keyVaultUrls": [ - -        "https://myfirstkeyvault.vault.azure.net", - -        "https://mysecondkeyvault.vault.azure.net" - -    ] -``` - -The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. - -## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises - -Follow the tasks in this section to configure an on-premises installation to use the Azure Key Vault feature. - -### Prerequisites - -- An Azure subscription with an Active Directory tenant. - - You sign up for an Azure subscription at [https://azure.microsoft.com](https://azure.microsoft.com). For information about getting an Azure AD tenant, see [How to get an Azure Active Directory tenant](/azure/active-directory/develop/active-directory-howto-tenant). - -- A security certificate - - As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vault, which requires the use of a certificate. The certificate is used to prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. - - In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. For example, on your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer, start Windows PowerShell as an administrator. Then at the prompt, run the following commands, one at a time: - - ```powershell - $cert = New-SelfSignedCertificate -Subject "BusinessCentralKeyVaultReader" -Provider "Microsoft Strong Cryptographic Provider" - ``` - - ```powershell - $cert.Thumbprint - ``` - - ```powershell - Export-Certificate -Cert $cert -FilePath c:\certs\BusinessCentralKeyVaultReader.cer - ``` - - These commands add a certificate called BusinessCentralKeyVaultReader to the computer's **LocalMachine** > **Personal (My)** certificate store. - -### Create the Azure Key Vault with secrets - -Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. - - - -There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. - -The easiest way is to use the Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal). - -For using other methods, see [Azure Key Vault Developer's Guide](/azure/key-vault/general/developers-guide#creating-and-managing-key-vaults). - -### Register a key vault reader application in Azure AD - -Next, register an application on your Azure AD tenant for reading secrets from the key vaults. When Azure AD authentication was set up, an Azure AD tenant was created in Azure. Reading key vaults requires a separate application registration with the Azure AD tenant. You can use an existing application if you have one. - -The steps in this task are done from the the [Azure portal](https://portal.azure.com). - -1. Sign-in to Azure portal at [portal.azure.com](http://portal.azure.com) and set the portal to your Azure Active Directory tenant. -2. Register an Azure AD application for the reading key vault. - - You add the new application by using the [Azure portal](https://portal.azure.com). For guidelines, see [Register your application with your Azure Active Directory tenant](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app). - - When you add an application to an Azure AD tenant, you must specify the following information: - - |Setting|Description| - |-------|-----------| - |Name|The name of your application as it will display to your users, such as *Business Central Key Vault Reader*.| - |Supported account types|Specifies which accounts that you would like your application to support. For purposes of this article, select **Accounts in this organizational directory only**. | - - - When completed, the **Overview** displays in the portal for the new application. - - Make a note of the **Display name** and/or **Application (client) ID**. You will use this information later. - -2. Upload the security certificate to the registered application. - - In this step, you upload the certificate file that you obtained as part of the prerequisites. - - From the key vault reader application overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions to locate and upload the certificate. - -### Grant the key vault reader application permission to key vaults - -In this task, you grant the key vault reader application permission to read secrets from your key vaults. - -The steps in this task are done from the the [Azure portal](https://portal.azure.com). - -1. Open the key vault in the portal. -2. Select **Access policies**, then **Add Access Policy**. -3. Set **Secret Permissions** to **Get**. -4. Select **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. -5. Select **Add**. -6. Select **Save**. - -At this point, the work in Azure is finished. - -### Configure the Business Central Server for the Apps Key Vault - -Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. - -1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. - - 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. - - For example, the following PowerShell command installs a certificate to the local machine's personal store: - - ```powershell - Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My - ``` - -2. Give the service account used by the [!INCLUDE[server](../developer/includes/server.md) instance permission to access the certificates private key. - - To do this using the MMC: - - 1. Open the MMC snap-in for certificates. See [How to: View Certificates with the MMC Snap-in](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in). - - 2. Expand the **Certificates \(Local Computer\)** node, expand the **Personal** node, and then select the **Certificates** subfolder. - - 3. In the right pane, right-click the certificate, select **All Tasks**, and then choose **Manage Private Keys**. - - 4. In the **Permissions** dialog box for the certificate, choose **Add**. - - 5. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], and then choose the **OK** button. - - 6. In the **Full Control** field, select **Allow**, and then choose the **OK** button. - -3. Make a note of the certificate thumbprint because you'll need it in the next step. See [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). - -4. Configure the [!INCLUDE[server](../developer/includes/server.md) instance. - - Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure to enable Azure key vault on the server instance: - - |Admin Tool Setting|Key name for CustomSetting.config|Value|Example| - |--------|-------------------------------|-----|-------| - |Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation|Set to the certificate store location where key vault certificate was stored.|LocalMachine| - |Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName|Set to the certificate store name where key vault certificate was stored.|MY| - |Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| - |Client ID|AzureKeyVaultClientId|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| - |Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| - - You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). - - For example, to use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Substitute brackets with your own values. - - ```powershell - Import-Module Microsoft.Dynamics.Nav.Management.dll - Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreLocation -KeyValue - Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreName -KeyValue - Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateThumbprint -KeyValue - Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientId -KeyValue - Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultAppSecretsPublisherValidationEnabled -KeyValue false - Restart-NAVServerInstance -ServerInstance - ``` - - > [!IMPORTANT] - > Setting the `AzureKeyVaultAppSecretsPublisherValidationEnabled` to false means the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. Please see the "Security considerations" section below for more details. - -At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. - -## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online +# Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. -### Create the Azure Key Vault with secrets +## Create the Azure Key Vault with secrets Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. When completed, the **Overview** displays in the portal for the new application. - Make a note of the **Display name** and/or **Application (client) ID**. You will use this information later. + Copt the **Display name** and/or **Application (client) ID**. You will use this information later. 2. Upload the security certificate to the registered application. @@ -110,7 +114,9 @@ At this point, the work in Azure is finished. ## Configure the Business Central Server for the Apps Key Vault -Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. +Next, you configure the [!INCLUDE[server](../developer/includes/server.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. + +To complete this task, you'll need the user name of the service account that runs the [!INCLUDE[server](../developer/includes/server.md)]. 1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. @@ -132,9 +138,9 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) 3. In the right pane, right-click the certificate, select **All Tasks**, and then choose **Manage Private Keys**. - 4. In the **Permissions** dialog box for the certificate, choose **Add**. + 4. In the **Security** dialog box, choose **Add**. - 5. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], and then choose the **OK** button. + 5. In the **Select Users, Computers, Service Accounts, or Groups** dialog box, enter the name of the dedicated domain user account that is associated with [!INCLUDE[server](../developer/includes/server.md)], for example, NETWORK SERVICE. Then, choose the **OK** button. 6. In the **Full Control** field, select **Allow**, and then choose the **OK** button. @@ -150,14 +156,13 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) |Client Certificate Store Name
(AzureKeyVaultClientCertificateStoreName)|Set to the certificate store name where key vault certificate was stored.|MY| |Client Certificate Thumbprint
(AzureKeyVaultClientCertificateThumbprint)|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| |Client ID
(AzureKeyVaultClientId)|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| - |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.|false| + |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.

**Important** If not enabled (`false`), the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security considerations](extension-key-vault.md#security). |false| You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). - For example, to use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Substitute brackets with your own values. + For example, to use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Substitute brackets with your own values. ```powershell - Import-Module Microsoft.Dynamics.Nav.Management.dll Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreLocation -KeyValue Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreName -KeyValue Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateThumbprint -KeyValue @@ -166,13 +171,21 @@ Next, you configure the [!INCLUDE[prodshort](../developer/includes/prodshort.md) Restart-NAVServerInstance -ServerInstance ``` + At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. + +## Monitoring and Troubleshooting + +Extensions + +The initialization failures provide information about problems with the set up of the App Key Vault. + ## See Also [Authentication and Credential Types](Users-Credential-Types.md) -[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) [Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file From af3caacf3d2823d5488feeb563204759251ab242 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 8 Jul 2020 12:15:03 +0200 Subject: [PATCH 062/950] fix --- .../administration/extension-key-vault.md | 60 +++++++++---------- .../devenv-system-application-overview.md | 1 + 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 32a4181d6c..8a5688bcec 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -16,37 +16,49 @@ Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make w These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. -Consider the credential as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where does the extension get the secret from? Well, this is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. +Consider the credential as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where does the extension get the secret from? This is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. ## Getting started -There are two parts to using secrets with extensions. +Getting extensions to use secrets from Azure Key Vault involves two areas of work: -- One or more key vaults for storing secrets must be set up in Azure, and [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service must be configured to access the key vaults. +- Setting up and configuring Azure Key Vault. - The setup is different for online and on-premises. For more information, see: - - [](setup-app-key-vault.md) - - [](setup-app-key-vault-onprem.md) + An extension can retrieve secrets from up to two different Azure Key Vaults. These key vaults must be first created in Azure, and then the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service is configured to access them. The setup process is different for online and on-premises. For more information, see: + - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) + - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises ](setup-app-key-vault-onprem.md) -- Extensions must be developed with code that specifies the key vaults -Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. +- Developing the extensions to use secrets from Azure Key Vault. -## Specifying Azure Key Vault in extensions + Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. In short, this work involves specifying the key vaults's URL and adding code to retrieve a secret from the key vault. -To use an Azure Key Vault for an extension, you specify the key vault the extension's manifest file (app.json), like this: +## Specify the Azure Key Vault in extensions -``` - +You specify the key vaults for an extension in the extension's manifest file (app.json). To specify a key vault, you add the `"keyVaultUrls"` to the app.json, and set the value to the key vault's URL. The following code snippet .: , like this: +```     "keyVaultUrls": [ -         "https://mykeyvault.vault.azure.net" -     ] +``` + +You can specify up to two key vaults in the app.json, as shown in the following code snippet: +``` +    "keyVaultUrls": [ +        "https://myfirstkeyvault.vault.azure.net", +        "https://mysecondkeyvault.vault.azure.net" +    ] ``` -Then, you can add code to the extension to read secrets from the key vault at runtime, like this: +Specifying two key vaults ensures a higher availability of secrets. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate both key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute because the other key vault will most likely be available. + + +## Add code to retrieve secrets the key vault + +Next, you add code to the extension for reads secrets from the key vault at runtime. To read secrets, you use the **Secrets** module of the System Application, specifically codeunit **3800 "App Key Vault Secret Provider"**. + +, like this. The system ``` page 50100 HelloWorldPage @@ -58,7 +70,7 @@ page 50100 HelloWorldPage trigger OnOpenPage(); begin if SecretProvider.TryInitializeFromCurrentApp() then begin - if SecretProvider.GetSecret('nameofsecret', SecretValue) then + if SecretProvider.GetSecret('', SecretValue) then Message('Retrieved secret: ' + SecretValue) else Message('Failed to retrieve secret') @@ -73,22 +85,6 @@ page 50100 HelloWorldPage The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. -## Specifying two Azure Key Vaults - -An extension manifest can specify up to two Azure Key Vaults, like this: - -``` - -    "keyVaultUrls": [ - -        "https://myfirstkeyvault.vault.azure.net", - -        "https://mysecondkeyvault.vault.azure.net" - -    ] -``` - -The use case for specifying two key vaults is to ensure high availability. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate the key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute without impact because the other key vault will most likely be available. ## Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises diff --git a/dev-itpro/developer/devenv-system-application-overview.md b/dev-itpro/developer/devenv-system-application-overview.md index b4977652a0..02a2875436 100644 --- a/dev-itpro/developer/devenv-system-application-overview.md +++ b/dev-itpro/developer/devenv-system-application-overview.md @@ -60,6 +60,7 @@ The list of modules is growing continuously. The following table lists and descr |Record Link Management|Provides helper functions for RecordLinks.|[ReadMe](https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/Record%20Link%20Management/README.md)| |Recurrence Schedule|Calculates when the next event will occur.|[ReadMe](https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/Recurrence%20Schedule/README.md)| |Satisfaction Survey|Shows a satisfaction survey.|[ReadMe](https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/Satisfaction%20Survey/README.md)| +|Secrets|Contains secret providers for reading secrets from the key vault that is specified by an extension or from other secret providers.|[ReadMe](https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/Secrets/README.md)| |Server Settings|Exposes methods that get settings from the server configuration file.|[ReadMe](https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/Server%20Settings/README.md)| |System Initialization|Runs non-business logic on user log-ins.|[ReadMe](https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/System%20Initialization/README.md)| |Tenant License State|Retrieves the current state of the tenant license.|[ReadMe](https://github.com/microsoft/ALAppExtensions/blob/master/Modules/System/Tenant%20License%20State/README.md)| From 473326794ad79dd3ce0cabfb37a93fd0adb738c2 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 8 Jul 2020 13:30:28 +0200 Subject: [PATCH 063/950] updates --- dev-itpro/TOC.md | 3 + dev-itpro/developer/devenv-app-key-vault.md | 119 ++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 dev-itpro/developer/devenv-app-key-vault.md diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index fdea48102a..d606f8e32f 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -209,6 +209,9 @@ ### [Discover Events Using the Event Recorder](developer/devenv-events-discoverability.md) ## [Notifications](developer/devenv-notifications-developing.md) ## [Task Scheduler](developer/devenv-task-scheduler.md) +## App Key Vaults for Secrets +### [Overview](developer/extension-key-vault.md) +### [Using Key Vault Secrets in Extensions](developer/devenv-app-key-vault.md) ## Tables ### [Tables Overview](developer/devenv-tables-overview.md) ### [Table Object](developer/devenv-table-object.md) diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md new file mode 100644 index 0000000000..2be1510a2b --- /dev/null +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -0,0 +1,119 @@ +--- +title: Azure Key Vaults with Business Central +description: Describes how to use an Azure Key vault with Business Central extensions. +ms.custom: na +ms.date: 04/01/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: jswymer +--- +# Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions + +This article describes how to code an extension to retrieve secrets from Azure Key Vaults. Secrets are a kind of credential used for authenticating en extension. Secrets are typically used when the extensions makes calls to web service. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](../administration/extension-key-vault.md). + +Developing an extension to use secrets from a key vaults involves two tasks as described in this article: + +- Specifying the Azure Key Vault in the extension's manifest. +- Adding code to retrieve the secrets from the key vault. + +Secrets are actually retrieved at runtime. + +## Preparation + +Using secrets requires that Azure Key Vault is available with secrets and configured for use by the the service. For more information, see [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) or [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises ](setup-app-key-vault-onprem.md). + +For coding, you'll need the URI the Azure Key Vault that stores the secret and the name of the secret itself. If you don't have this information, you can get it from Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal). + +## Specify the Azure Key Vault in extensions + +You specify the key vaults for an extension in the extension's manifest file (app.json). To specify a key vault, you add the `"keyVaultUrls"` to the app.json, and set the value to the key vault's URL. For example, the following code snippet specifies a key vault that has the URI `https://mykeyvault.vault.azure.net`: + +``` +    "keyVaultUrls": [ +        "https://mykeyvault.vault.azure.net" +    ] +``` + +You can specify up to two key vaults in the app.json, as shown in the following example code snippet: + +``` +    "keyVaultUrls": [ +        "https://myfirstkeyvault.vault.azure.net", +        "https://mysecondkeyvault.vault.azure.net" +    ] +``` + +Specifying two key vaults ensures a higher availability of secrets. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate both key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute because the other key vault will most likely be available. + + +## Add code to retrieve secrets the key vault + +Next, you add code to the extension for reading secrets from the key vault at runtime. To read secrets, you use the **Secrets** module of the System Application, specifically codeunit **3800 "App Key Vault Secret Provider"**. This codeunit includes two methods: + +| Method |Description| +|--------|-----------| +| `TryInitializeFromCurrentApp(): Boolean`|Identifies the calling extension and initializes the codeunit with the key vaults specified in the extension's manifest.| +| `GetSecret(SecretName: Text, var SecretValue: Text): Boolean`|Retrieves the value of a specific secret from one of the app's key vaults.| + +Look at following example for a simple page object. The code retrieves the value of the secret named **MySecret** in app key vault: + +``` +page 50100 HelloWorldPage +{ + var + SecretProvider: Codeunit "App Key Vault Secret Provider"; + SecretValue: Text; + + trigger OnOpenPage(); + begin + if SecretProvider.TryInitializeFromCurrentApp() then begin + if SecretProvider.GetSecret('MySecret', SecretValue) then + Message('Retrieved secret: ' + SecretValue) + else + Message('Failed to retrieve secret') + end + else + Message('ERROR: ' + GetLastErrorText()); + end; +} +``` + +The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. + +## Security considerations + +Keep the following information in mind when you use the App Key Vault feature. + +### Use NonDebuggable + +As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. + +### Don't pass the App Key Vault Secret Provider to untrusted code + +Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. + +### Run with publisher validation + +In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. + +When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: + +`Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId` + +Only if this check is satisfied will the initialization succeed. + +So how does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: + +Publish-NavApp … -PublisherAzureActiveDirectoryTenantId + +In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. + + +## See Also + +[Authentication and Credential Types](Users-Credential-Types.md) +[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) +[Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file From 3267a20b57b5452171572579ac629dddc11e286a Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 8 Jul 2020 13:35:16 +0200 Subject: [PATCH 064/950] Update extension-key-vault.md --- dev-itpro/administration/extension-key-vault.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 8a5688bcec..2d7d08f830 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -2,7 +2,7 @@ title: Azure Key Vaults with Business Central description: Describes how to use an Azure Key vault with Business Central extensions. ms.custom: na -ms.date: 04/01/2020 +ms.date: 07/08/2020 ms.reviewer: na ms.suite: na ms.tgt_pltfrm: na @@ -32,6 +32,9 @@ Getting extensions to use secrets from Azure Key Vault involves two areas of wor Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. In short, this work involves specifying the key vaults's URL and adding code to retrieve a secret from the key vault. + See [Using App Key Vaults with Extensions](developer/devenc-app-key-vault.md). + + - + - When completed, the **Overview** displays in the portal for the new application. + + -There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. + ## See Also [Authentication and Credential Types](Users-Credential-Types.md) From b2cbc71f76c19abeb1142e66f7886074f8b301f4 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 8 Jul 2020 13:37:18 +0200 Subject: [PATCH 065/950] Update extension-key-vault.md --- dev-itpro/administration/extension-key-vault.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 2d7d08f830..cbabc01d0b 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -25,6 +25,7 @@ Getting extensions to use secrets from Azure Key Vault involves two areas of wor - Setting up and configuring Azure Key Vault. An extension can retrieve secrets from up to two different Azure Key Vaults. These key vaults must be first created in Azure, and then the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service is configured to access them. The setup process is different for online and on-premises. For more information, see: + - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises ](setup-app-key-vault-onprem.md) @@ -34,6 +35,7 @@ Getting extensions to use secrets from Azure Key Vault involves two areas of wor See [Using App Key Vaults with Extensions](developer/devenc-app-key-vault.md). + ## Security considerations Keep the following information in mind when you use the App Key Vault feature. @@ -354,7 +356,7 @@ Publish-NavApp … -PublisherAzureActiveDirectoryTenantId In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. ---> + ## See Also [Authentication and Credential Types](Users-Credential-Types.md) From f03f364097460a027402bdd35aa47887fba8ced4 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 8 Jul 2020 16:58:09 +0200 Subject: [PATCH 066/950] fix --- dev-itpro/administration/extension-key-vault.md | 14 +++++++------- .../telemetry-extension-key-vault-trace.md | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index cbabc01d0b..3f1a38e832 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -22,18 +22,18 @@ Consider the credential as a kind of secret to the extension. A secret shouldn't Getting extensions to use secrets from Azure Key Vault involves two areas of work: -- Setting up and configuring Azure Key Vault. +### Setting up and configuring Azure Key Vault - An extension can retrieve secrets from up to two different Azure Key Vaults. These key vaults must be first created in Azure, and then the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service is configured to access them. The setup process is different for online and on-premises. For more information, see: +An extension can retrieve secrets from up to two different Azure Key Vaults. These key vaults must be first created in Azure. Then, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service must be configured to access key vaults. The setup process is different for online and on-premises. For more information, see: - - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) - - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises ](setup-app-key-vault-onprem.md) +- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) +- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises ](setup-app-key-vault-onprem.md) -- Developing the extensions to use secrets from Azure Key Vault. +### Developing the extensions to use secrets from Azure Key Vault - Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. In short, this work involves specifying the key vaults's URL and adding code to retrieve a secret from the key vault. +Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. In short, this work involves specifying the key vault's URL and adding code to retrieve a secret from the key vault. - See [Using App Key Vaults with Extensions](developer/devenc-app-key-vault.md). +For more information, see [Using App Key Vaults with Extensions](developer/devenv-app-key-vault.md). ## Security considerations -Keep the following information in mind when you use the App Key Vault feature. +Keep the following information in mind when you use the App Key Vault feature with your extensions. -### Use NonDebuggable +### Mark Methods as NonDebuggable -As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. +When your code works with secrets, whether from a key vault or from Isolated Storage, block the ability to debug relevant methods by using the [NonDebuggable Attribute](../methods/devenv-nondebuggable-attribute.md). This prevents other partners from debugging into your code and seeing the secrets. ### Don't pass the App Key Vault Secret Provider to untrusted code -Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. +Once the **App Key Vault Secret Provider** codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another method, then that method can also use it. If you pass the codeunit to a method in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. ### Run with publisher validation -In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. +For In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: @@ -356,9 +356,6 @@ Publish-NavApp … -PublisherAzureActiveDirectoryTenantId In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. - ## See Also -[Authentication and Credential Types](Users-Credential-Types.md) -[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) [Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file From 24667df3780a961ed69a71ef84aba92dbaa83b00 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 8 Jul 2020 23:03:59 +0200 Subject: [PATCH 071/950] updates --- .../configure-server-instance.md | 12 ++++----- .../administration/extension-key-vault.md | 27 ++++++++++++++----- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 10d2e15a78..59bf6ee5ce 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -223,14 +223,14 @@ The following table describes fields on the **Management Services** tab in the [ The following table describes fields on the **Azure Key Vault Client Identity** tab in the [!INCLUDE[admintool](../developer/includes/admintool.md)]. -These settings are used when you want to use Azure Key Vault to store extension secrets and data encryption keys. For more information, see [Extension Key Vaults](extension-key-vault.md) and [Data Encryption](../developer/devenv-encrypting-data.md). +These settings are used when you want to use Azure Key Vaults to store extension secrets and data encryption keys. For more information, see [Setting up App Key Vaults ](setup-app-key-vault-onprem.md) and [Data Encryption](../developer/devenv-encrypting-data.md). | Setting |Key Name| Description | |-----------|--------|---------------| -| Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation| Specifies the location of the certificate store for the Key Vault client certificate.

**LocalMachine** specifies that the certificate is stored in a certificate store for the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

**CurrentUser** specifies that the certificate is stored in a certificate store for your account on the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

Default: LocalMachine
Dynamically Updatable: No| -| Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName| Specifies the certificate store where the Key Vault client certificate is stored.

Default: My
Dynamically Updatable: No| -| Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint| Specifies the thumbprint of the Key Vault client certificate

Default: My
Dynamically Updatable: No| -| Client ID |AzureKeyVaultClientId| Specifies the unique identifier (GUID) of the Key Vault client application in Microsoft Azure.

Default: 00000000-0000-0000-0000-000000000000
Dynamically Updatable: No | +| Client Certificate Store Location|AzureKeyVaultClientCertificateStoreLocation| Specifies the location of the certificate store where the key vault reader certificate is stored.

**LocalMachine** specifies that the certificate is stored in a certificate store for the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

**CurrentUser** specifies that the certificate is stored in a certificate store for your account on the computer that the [!INCLUDE[server](../developer/includes/server.md)] is running on.

Default: LocalMachine
Dynamically Updatable: No| +| Client Certificate Store Name|AzureKeyVaultClientCertificateStoreName| Specifies the certificate store where the key vault reader certificate is stored.

Default: My
Dynamically Updatable: No| +| Client Certificate Thumbprint|AzureKeyVaultClientCertificateThumbprint| Specifies the thumbprint of the certificate used by the key vault reader application in Azure.

Default: My
Dynamically Updatable: No| +| Client ID |AzureKeyVaultClientId| Specifies the appication (client) ID of the key vault reader application in Azure. The value is a GUID.

Default: 00000000-0000-0000-0000-000000000000
Dynamically Updatable: No | ## Azure Key Vault Extension Secrets Tab Settings @@ -238,7 +238,7 @@ The following table describes fields on the **Azure Key Vault Extension Secrets* | Setting |Key Name| Description | |-----------|--------|---------------| -|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** enables validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** disables publisher validation. **Important** When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security Considerations](extension-key-vault.md#security).
An extension publisher's identity is specified when the extension is published.

Default: false
Dynamically Updatable: No| +|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** turns on validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** turns off validation. **Important** When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security Considerations](extension-key-vault.md#security).
An extension publisher's identity is specified when the extension is published. However, the validation is done at runtime. This setting doesn't affect extensions that don't use app key vault secrets.

Default: true
Dynamically Updatable: No| ## Azure Active Directory (Azure AD) Settings diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 9465cc1137..7c2bb4ed7f 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -340,19 +340,32 @@ When your code works with secrets, whether from a key vault or from Isolated Sto Once the **App Key Vault Secret Provider** codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another method, then that method can also use it. If you pass the codeunit to a method in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. -### Run with publisher validation +### Run publisher validation -For In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. +For on-premises deployments, you can configure [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to run with or without publisher validation on key vault secret providers. Publisher validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. -When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: +#### How it works -`Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId` +Publisher validation is done by comparing the Azure AD tenant ID of the Azure Key Vault provider with that of the extension's publisher. It works this way: -Only if this check is satisfied will the initialization succeed. +1. When an extension is published by using the [Publish-NAVApp cmdlet](/powershell/module/microsoft.dynamics.nav.apps.management/publish-navapp), the publisher can provide their Azure AD tenant ID by setting the `-PublisherAzureActiveDirectoryTenantId` parameter: -So how does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: + ```powershell + Publish-NavApp -ServerInstance -Path -PublisherAzureActiveDirectoryTenantId + ``` + + > [!NOTE] + > An error will not occur if `-PublisherAzureActiveDirectoryTenantId` isn't set. There is nothing preventing someone from publishing the extension at this point. + +2. When the extension tries to initialize the **App Key Vault Secret Provider** codeunit, the system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: + + - If they match, initialization succeeds + - If the don't match, an error occurs. + +#### Turning off publisher validation is turned on by default, which is the recommended setting + +Publisher validation is turned on by default, which is the recommended setting. You -Publish-NavApp … -PublisherAzureActiveDirectoryTenantId In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. From eba0de3fe296a70c860c207fd95eca8e0f41543f Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 00:07:06 +0200 Subject: [PATCH 072/950] updates --- .../configure-server-instance.md | 2 +- .../administration/extension-key-vault.md | 18 +++++++++--------- .../setup-app-key-vault-onprem.md | 4 ++-- dev-itpro/developer/devenv-app-key-vault.md | 2 ++ 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index 59bf6ee5ce..d4924e5920 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -238,7 +238,7 @@ The following table describes fields on the **Azure Key Vault Extension Secrets* | Setting |Key Name| Description | |-----------|--------|---------------| -|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** turns on validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** turns off validation. **Important** When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security Considerations](extension-key-vault.md#security).
An extension publisher's identity is specified when the extension is published. However, the validation is done at runtime. This setting doesn't affect extensions that don't use app key vault secrets.

Default: true
Dynamically Updatable: No| +|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** turns on validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** turns off validation. **Important** For security reasons, we recommend that you don't turn this setting off, unless you trust all etxtensions that might get installed on the tenant.
An extension publisher's identity is specified when the extension is published. However, the validation is done at runtime. This setting doesn't affect extensions that don't use app key vault secrets. For more information, see [App Key Vaults - Security Considerations](extension-key-vault.md#security).

Default: true
Dynamically Updatable: No| ## Azure Active Directory (Azure AD) Settings diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 7c2bb4ed7f..c8bd986c54 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -14,9 +14,7 @@ author: jswymer Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. -These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. These credentials enable the other service to accept or reject the call. - -Consider the credential as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where does the extension get the secret from? This is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. +These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? This is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. ## Getting started @@ -27,7 +25,7 @@ Getting extensions to use secrets from Azure Key Vault involves two areas of wor An extension can retrieve secrets from up to two different Azure Key Vaults. These key vaults must be first created in Azure. Then, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service must be configured to access key vaults. The setup process is different for online and on-premises. For more information, see: - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) -- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises ](setup-app-key-vault-onprem.md) +- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises](setup-app-key-vault-onprem.md) ### Developing the extensions to use secrets from Azure Key Vault @@ -342,7 +340,10 @@ Once the **App Key Vault Secret Provider** codeunit has been initialized, it can ### Run publisher validation -For on-premises deployments, you can configure [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to run with or without publisher validation on key vault secret providers. Publisher validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. +For on-premises deployments, you can configure [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabledPublisher) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. + +> [!TIP] +> With a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online production environment, publisher validation is not performed for per-tenant extensions. Publisher validation is done automatically for onboarded AppSource extensions. #### How it works @@ -362,12 +363,11 @@ Publisher validation is done by comparing the Azure AD tenant ID of the Azure Ke - If they match, initialization succeeds - If the don't match, an error occurs. -#### Turning off publisher validation is turned on by default, which is the recommended setting - -Publisher validation is turned on by default, which is the recommended setting. You +#### Turning off publisher validation +Publisher validation is turned on by default, which is the recommended setting. If it's turned off, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. So, don't turn off publisher validation unless you trust the extensions that can be potentially installed. -In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. +For information about how to turn publisher validation on or off, see [Configuring Business Central Server](configure-server-instance.md). ## See Also diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index 0480e1aa55..d7e6e1fbe4 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -156,7 +156,7 @@ To complete this task, you'll need the user name of the service account that run |Client Certificate Store Name
(AzureKeyVaultClientCertificateStoreName)|Set to the certificate store name where key vault certificate was stored.|MY| |Client Certificate Thumbprint
(AzureKeyVaultClientCertificateThumbprint)|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| |Client ID
(AzureKeyVaultClientId)|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| - |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers. An extension publisher's identity is specified when the extension is published. Enabling this setting blocks attempts in AL to read secrets from another publisher's key vault.

**Important** If not enabled (`false`), the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security considerations](extension-key-vault.md#security). |false| + |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers.

Enabling this setting (`true`) blocks attempts in AL to read secrets from another publisher's key vault. When extensions that use key vault secrets are published, you must provide your Azure AD tenant ID.

**Important** We recommend that you only disable this setting If you disable this setting (`false`), the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security considerations](extension-key-vault.md#security). |true| You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). @@ -167,7 +167,7 @@ To complete this task, you'll need the user name of the service account that run Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreName -KeyValue Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateThumbprint -KeyValue Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientId -KeyValue - Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultAppSecretsPublisherValidationEnabled -KeyValue false + Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultAppSecretsPublisherValidationEnabled -KeyValue Restart-NAVServerInstance -ServerInstance ``` diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md index 735ac4338f..aeb76ffa0a 100644 --- a/dev-itpro/developer/devenv-app-key-vault.md +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -111,7 +111,9 @@ Publish-NavApp … -PublisherAzureActiveDirectoryTenantId In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. +If you don't trust all extensions that might get installed, you should enable publisher validation. The Business Central SaaS service is configured to validate publish +When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. ## See Also [Authentication and Credential Types](Users-Credential-Types.md) From f312d6e9f5ecc574e5e251a0a752b52eb0068e24 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 00:10:15 +0200 Subject: [PATCH 073/950] Update extension-key-vault.md --- dev-itpro/administration/extension-key-vault.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index c8bd986c54..40196de077 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -14,7 +14,7 @@ author: jswymer Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. -These web service calls are typically authenticated, which means the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? This is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. +These web service calls are typically authenticated, which means the extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? This is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. ## Getting started @@ -22,7 +22,7 @@ Getting extensions to use secrets from Azure Key Vault involves two areas of wor ### Setting up and configuring Azure Key Vault -An extension can retrieve secrets from up to two different Azure Key Vaults. These key vaults must be first created in Azure. Then, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service must be configured to access key vaults. The setup process is different for online and on-premises. For more information, see: +An extension can retrieve secrets from two different Azure Key Vaults. These key vaults must be first created in Azure. Then, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service must be configured to access key vaults. The setup process is different for online and on-premises. For more information, see: - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises](setup-app-key-vault-onprem.md) @@ -356,9 +356,9 @@ Publisher validation is done by comparing the Azure AD tenant ID of the Azure Ke ``` > [!NOTE] - > An error will not occur if `-PublisherAzureActiveDirectoryTenantId` isn't set. There is nothing preventing someone from publishing the extension at this point. + > An error won't occur if `-PublisherAzureActiveDirectoryTenantId` isn't set. There is nothing preventing you from publishing the extension at this point. -2. When the extension tries to initialize the **App Key Vault Secret Provider** codeunit, the system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: +2. When the extension is run and tries to initialize the **App Key Vault Secret Provider** codeunit, the system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: - If they match, initialization succeeds - If the don't match, an error occurs. From 2678b3f804ef26c199451d468ab4dafd0f547283 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 08:53:45 +0200 Subject: [PATCH 074/950] updates --- .../configure-server-instance.md | 8 ++--- .../administration/extension-key-vault.md | 30 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index d4924e5920..645f9812d3 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -68,11 +68,11 @@ The following table describes fields on the **General** tab in the [!INCLUDE[adm |Application Insights Instrumentation Key|ApplicationInsightsInstrumentationKey|Specifies the instrumentation key of the Microsoft Azure Application Insights resource to use for gathering and analyzing telemetry data emitted by the server instance. When this setting is configured, the server instance will send telemetry data to Application Insights for analysis and presentation.

This setting only applies to a server instance that is configured as a single-tenant instance (**Multitenant** setting is disabled). For a multitenant server instance, this setting is ignored. You set the Application Insights instrumentation key on a per-tenant basis, when you mount tenants.

For more information, see [Enable Sending Telemetry to Application Insights](telemetry-enable-application-insights.md).

Default: empty
Dynamically Updatable: No| |Build Restriction|ClientBuildRestriction|Specifies what happens when a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] client tries to connect to the [!INCLUDE[server](../developer/includes/server.md)] instance when the client is running a different build version of [!INCLUDE[prodshort](../developer/includes/prodshort.md)] than the server instance.

Values:

**AlwaysConnect**

**WarnClient**
Before connecting the client to the server instance, a message appears that informs the user that the build versions for the client and server instance are different. The user can choose to continue or cancel the connection.

**DoNotAllow**
A message appears that informs the user that the client and server instance build versions are different. The client doesn't connect to the server instance.

**Note:** With the [!INCLUDE[nav_web](../developer/includes/nav_web_md.md)] and [!INCLUDE[nav_tablet](../developer/includes/nav_tablet_md.md)], this setting compares the build version of the [!INCLUDE[webserver](../developer/includes/webserver.md)] on IIS with the [!INCLUDE[server](../developer/includes/server.md)] instance. It controls the connection between [!INCLUDE[webserver](../developer/includes/webserver.md)] and the server instance.

Default: WarnClient
Dynamically Updatable: No| |Certificate Thumbprint|ServicesCertificateThumbprint|If you use security certificates to protect communications between [!INCLUDE[server](../developer/includes/server.md)] and client services or web services over an open or wide-area network, you must provide the certificate thumbprint to [!INCLUDE[server](../developer/includes/server.md)] by updating this setting. For more information, see [Using Security Certificates](../deployment/implement-security-certificates-production-environment.md).

Default:
Dynamically Updatable: No| -|Compile and Load Business Application|CompileBusinessApplicationAtStartup|Specifies whether the server instance compiles business application assemblies and loads them to cache memory when it starts. The assemblies are then retrieved from memory when requested by a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] client.

This setting reduces the time it takes to load application objects the first time the client requests them after the server instance has started. However, it will also slightly increase the memory usage by the server instance.

When the server instance starts for the first time, it compiles the business application assemblies and loads them to the cache memory of the computer. The assemblies, along with metadata such object timestamp information, are also stored to a temporary folder on the computer's file system. When the server instance is restarted, it compares the assemblies stored in memory with corresponding objects in the connected database. An assembly will be reused if the following conditions are met:

- The connected database is the same as before, based on the *databasemagic* field in the property table.

- The object time stamp that is recorded on the compiled assembly matches the object timestamp in metadata of the connected database.

If the conditions aren't met for an assembly or an assembly for an object in the database isn't found in the memory, then a new assembly is built and stored for reuse to cache memory and the file system of the server instance compute for reuse.

If you disable this setting, individual assemblies will be compiled on-demand as application objects are requested by the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] client. The compiled assemblies won't be reused on later server instance restarts.

Notes:
  • This setting doesn't apply to query objects.
  • Assembly compilation happens asynchronously.
  • On average, all application objects will be loaded within the first few minutes that the server instance operates.

Default: Enabled
Dynamically Updatable: No| -|Credential Type|ClientServicesCredentialType|Specifies the authentication mechanism for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] users of the [!INCLUDE[server](../developer/includes/server.md)] instance.

The options are **Windows**, **Username**, **NavUserPassword**, **AccessControlService**, and **None**. For more information, see [Authentication and User Credential Types](Users-Credential-Types.md).

If you choose **AccessControlService**, you must specify a federation metadata location for use with Azure AD. If you choose **NavUserPassword** and specify a token signing key, you can use both NavUserPassword and AccessControlService.

Notes:
  • **None** is for internal use on system sessions and typically shouldn't not be used. If you choose **None**, then the [!INCLUDE[server](../developer/includes/server.md)] instance can't start.
  • **ExchangeIdentity** and **TaskScheduler** are for internal use only, and shouldn't be used.

Default: Windows
Dynamically Updatable: No| +|Compile and Load Business Application|CompileBusinessApplicationAtStartup|Specifies whether the server instance compiles business application assemblies and loads them to cache memory when it starts. The assemblies are then retrieved from memory when requested by a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] client.

This setting reduces the time it takes to load application objects the first time the client requests them after the server instance has started. However, it will also slightly increase the memory usage by the server instance.

When the server instance starts for the first time, it compiles the business application assemblies and loads them to the cache memory of the computer. The assemblies, along with metadata such object timestamp information, are also stored to a temporary folder on the computer's file system. When the server instance is restarted, it compares the assemblies stored in memory with corresponding objects in the connected database. An assembly will be reused if the following conditions are met:

- The connected database is the same as before, based on the *databasemagic* field in the property table.

- The object time stamp that is recorded on the compiled assembly matches the object timestamp in metadata of the connected database.

If the conditions aren't met for an assembly or an assembly for an object in the database isn't found in the memory, then a new assembly is built and stored for reuse to cache memory and the file system of the server instance compute for reuse.

If you disable this setting, individual assemblies will be compiled on-demand as application objects are requested by the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] client. The compiled assemblies won't be reused on later server instance restarts.

Notes:
  • This setting doesn't apply to query objects.
  • Assembly compilation happens asynchronously.
  • On average, all application objects will be loaded within the first few minutes that the server instance operates.

Default: Enabled
Dynamically Updatable: No| +|Credential Type|ClientServicesCredentialType|Specifies the authentication mechanism for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] users of the [!INCLUDE[server](../developer/includes/server.md)] instance.

The options are **Windows**, **Username**, **NavUserPassword**, **AccessControlService**, and **None**. For more information, see [Authentication and User Credential Types](Users-Credential-Types.md).

If you choose **AccessControlService**, you must specify a federation metadata location for use with Azure AD. If you choose **NavUserPassword** and specify a token signing key, you can use both NavUserPassword and AccessControlService.

Notes:
  • **None** is for internal use on system sessions and typically shouldn't be used. If you choose **None**, then the [!INCLUDE[server](../developer/includes/server.md)] instance can't start.
  • **ExchangeIdentity** and **TaskScheduler** are for internal use only, and shouldn't be used.

Default: Windows
Dynamically Updatable: No| |Data Cache Size|DataCacheSize|The contextual size of the data cache. The value must be in the range 1-20.

Default: 9
Dynamically Updatable: Yes| |Default Client|DefaultClient|Specifies the client type that is used to generate URLs when the client type is set to Default.

The options are **Conversational**, **Windows**, **Web**, **SOAP**, and **OData**.

Default: Conversational
Dynamically Updatable: No| -|Default Language|DefaultLanguage|Specifies which of the installed [!INCLUDE[prodshort](../developer/includes/prodshort.md)] languages on the server instance will be used as the default language in the clients. Set the value to a valid language culture name, such en-US or da-DK.

In the wb and tablet clients, this setting determines the language that is used if the web browser's language setting doesn't match any installed language or a language in the **Supported Languages** setting. In the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Windows client, this value is used if the language setting of the computer doesn't have a match.

If there are application-specific configuration settings, this setting will be overridden by the default language setting that is specified in application-specific configuration file. For more information, see [Set-NAVServerAppConfiguration cmdlet](https://go.microsoft.com/fwlink/?linkid=827798).

Default: en-US
Dynamically Updatable: No| +|Default Language|DefaultLanguage|Specifies which of the installed [!INCLUDE[prodshort](../developer/includes/prodshort.md)] languages on the server instance will be used as the default language in the clients. Set the value to a valid language culture name, such en-US or da-DK.

In the web and tablet clients, this setting determines the language used if the browser's language setting doesn't match any installed language or a language in the **Supported Languages** setting. In the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Windows client, this value is used if the language setting of the computer doesn't have a match.

If there are application-specific configuration settings, this setting will be overridden by the default language setting that is specified in application-specific configuration file. For more information, see [Set-NAVServerAppConfiguration cmdlet](https://go.microsoft.com/fwlink/?linkid=827798).

Default: en-US
Dynamically Updatable: No| | Diagnostic Trace Level |TraceLevel| Specifies the lowest severity level of custom telemetry events to be emitted and recorded in the event log for the [!INCLUDE[server](../developer/includes/server.md)] instance. The events include system telemetry trace events and custom telemetry events. Telemetry events have IDs from 700-706.

The setting has the following values, which correspond to the event severity levels (listed from highest to lowest level): **Critical**, **Error**, **Warning**, **Normal** (this value corresponds to the **Information** level), **Verbose**, and **Off**.

You use this setting to filter out lower-level events from the log. For example, if you set this setting to **Error**, only **Error** and **Critical** events will be logged.

Set to **Off** if you don't want to record telemetry events. When set to **Off**, events aren't emitted.

**Note:** Telemetry trace events are recorded in the [!INCLUDE[server](../developer/includes/server.md)] channel logs, which you can see in Event Viewer, under **Applications and Services Logs** > **Microsoft** > **Dynamics365BusinessCentral** > **Common** > **Admin**.

Default: Normal
Dynamically Updatable: Yes| |Diagnostic Trace Level for External Proxies|ExternalTraceLevel|Specifies the lowest severity level of telemetry events from external proxies that you want the [!INCLUDE[server](../developer/includes/server.md)] instance to emit if an error related to the external system occurs on the server instance. This setting pertains to systems and components that [!INCLUDE[prodshort](../developer/includes/prodshort.md)] integrates with, like [!INCLUDE[crm_md](../developer/includes/crm_md.md)] (CRM/Xrm).

The server instance listens for event traces from the external proxy. If an error occurs on the server instance, it will emit the last 10 telemetry trace events from the external proxy. The trace events can then be recorded in the Windows event log or picked up by other event trace collection tools.

The setting has the following values, which correspond to the event severity levels (listed from highest to lowest level): **Critical**, **Error**, **Warning**, **Information**, **Verbose**, and **Off**.

Events that have a lower severity level than the set value won't be emitted. For example, if you set this setting to **Error**, only **Error** and **Critical** events will be emitted. Set to **Off** if you don't want to emit any of these events.

Default: Error
Dynamically Updatable: Yes| |Disable Token-Signing Certificate Validation|DisableTokenSigningCertificateValidation|Specifies whether to enable or disable the validation of the token-signing certificate used by Active Directory Federation Services (AD FS). If the check box is cleared (or the value set to `false`), the validation is enabled. If the check box is selected (or the value is set to `true`), then validation is disabled.

Disable token signing certificate validation when configuring Azure Active Directory authentication with single sign-on.

Default: Checkbox cleared; set to `false`.
Dynamically Updatable: No | @@ -238,7 +238,7 @@ The following table describes fields on the **Azure Key Vault Extension Secrets* | Setting |Key Name| Description | |-----------|--------|---------------| -|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** turns on validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** turns off validation. **Important** For security reasons, we recommend that you don't turn this setting off, unless you trust all etxtensions that might get installed on the tenant.
An extension publisher's identity is specified when the extension is published. However, the validation is done at runtime. This setting doesn't affect extensions that don't use app key vault secrets. For more information, see [App Key Vaults - Security Considerations](extension-key-vault.md#security).

Default: true
Dynamically Updatable: No| +|Enable Publisher Validation|AzureKeyVaultAppSecretsPublisherValidationEnabled| Specifies whether extensions can only use key vaults that belong to their publishers.
  • **true** turns on validation. Extensions can only use key vaults that belong to their publishers. This setting blocks attempts in AL to read secrets from another publisher's key vault.
  • **false** turns off validation. **Important** For security reasons, we recommend that you don't turn this setting off, unless you trust all etxtensions that might get installed on the tenant.
An extension publisher's identity is specified when the extension is published. However, the validation is done at runtime. This setting doesn't affect extensions that don't use app key vault secrets. For more information, see [App Key Vaults - Security Considerations](extension-key-vault.md#validation).

Default: true
Dynamically Updatable: No| ## Azure Active Directory (Azure AD) Settings diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 40196de077..11f896bd90 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -14,15 +14,15 @@ author: jswymer Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. -These web service calls are typically authenticated, which means the extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? This is where Azure Key Vaults comes into play. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, like passwords and database connection strings, enabling you to control access and distribution of the secrets. +These web service calls are typically authenticated, which means the extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? Here is where Azure Key Vaults is used. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, enabling you to control access and distribution of the secrets. ## Getting started Getting extensions to use secrets from Azure Key Vault involves two areas of work: -### Setting up and configuring Azure Key Vault +### Setting up and configuring Azure Key Vaults -An extension can retrieve secrets from two different Azure Key Vaults. These key vaults must be first created in Azure. Then, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service must be configured to access key vaults. The setup process is different for online and on-premises. For more information, see: +An extension can retrieve secrets from one or two different Azure Key Vaults. These key vaults must be created in Azure, and the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service configured to access key vaults. The setup process is different for online and on-premises. For more information, see: - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) - [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises](setup-app-key-vault-onprem.md) @@ -326,28 +326,33 @@ Send an email to TODO@microsoft.com to start the onboarding process. This should The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. --> -## Security considerations +## Security considerations Keep the following information in mind when you use the App Key Vault feature with your extensions. ### Mark Methods as NonDebuggable -When your code works with secrets, whether from a key vault or from Isolated Storage, block the ability to debug relevant methods by using the [NonDebuggable Attribute](../methods/devenv-nondebuggable-attribute.md). This prevents other partners from debugging into your code and seeing the secrets. +When your code works with secrets, whether from a key vault or from Isolated Storage, block the ability to debug relevant methods by using the [NonDebuggable Attribute](../methods/devenv-nondebuggable-attribute.md). It prevents other partners from debugging into your code and seeing the secrets. ### Don't pass the App Key Vault Secret Provider to untrusted code -Once the **App Key Vault Secret Provider** codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another method, then that method can also use it. If you pass the codeunit to a method in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. +Once the **App Key Vault Secret Provider** codeunit has been initialized, it can be used to get secrets. -### Run publisher validation +- If you pass the codeunit to another method, then that method is also able use it. +- If you pass the codeunit to a method in another extension, then the other extension can also use the secret provider to get secrets. -For on-premises deployments, you can configure [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabledPublisher) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. +These conditions may not be what you want, so be careful with who you pass the secret provider. + +### Run publisher validation + +For on-premises deployments, you can configure [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the server's **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabledPublisher) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. > [!TIP] > With a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online production environment, publisher validation is not performed for per-tenant extensions. Publisher validation is done automatically for onboarded AppSource extensions. #### How it works -Publisher validation is done by comparing the Azure AD tenant ID of the Azure Key Vault provider with that of the extension's publisher. It works this way: +Publisher validation is done by comparing the key vault secret provider's Azure AD tenant ID with the extension publisher's Azure AD tenant ID. It works this way: 1. When an extension is published by using the [Publish-NAVApp cmdlet](/powershell/module/microsoft.dynamics.nav.apps.management/publish-navapp), the publisher can provide their Azure AD tenant ID by setting the `-PublisherAzureActiveDirectoryTenantId` parameter: @@ -358,10 +363,11 @@ Publisher validation is done by comparing the Azure AD tenant ID of the Azure Ke > [!NOTE] > An error won't occur if `-PublisherAzureActiveDirectoryTenantId` isn't set. There is nothing preventing you from publishing the extension at this point. -2. When the extension is run and tries to initialize the **App Key Vault Secret Provider** codeunit, the system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: +2. When the extension runs, it tries to initialize the **App Key Vault Secret Provider** codeunit. +3. The system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: - - If they match, initialization succeeds - - If the don't match, an error occurs. + - If they match, initialization succeeds. + - If they don't match, an error occurs. #### Turning off publisher validation From 7bc6774ec6a450f1c40d8028f92bbb38a2aa8df0 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 09:08:24 +0200 Subject: [PATCH 075/950] Update setup-app-key-vault-onprem.md --- .../setup-app-key-vault-onprem.md | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index d7e6e1fbe4..81c17e2a3f 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -146,17 +146,17 @@ To complete this task, you'll need the user name of the service account that run 3. Make a note of the certificate thumbprint because you'll need it in the next step. See [How to: Retrieve the Thumbprint of a Certificate](/dotnet/framework/wcf/feature-details/how-to-retrieve-the-thumbprint-of-a-certificate). -4. Configure the [!INCLUDE[server](../developer/includes/server.md) instance. +4. Configure the [!INCLUDE[server](../developer/includes/server.md)] instance. Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure to enable Azure key vault on the server instance: - |Setting
(key name)|Value|Example| - |--------|-------------------------------|-----|-------| - |Client Certificate Store Location
(AzureKeyVaultClientCertificateStoreLocation)|Set to the certificate store location where key vault certificate was stored.|LocalMachine| - |Client Certificate Store Name
(AzureKeyVaultClientCertificateStoreName)|Set to the certificate store name where key vault certificate was stored.|MY| - |Client Certificate Thumbprint
(AzureKeyVaultClientCertificateThumbprint)|Set to the thumbprint for the key vault certificate.|649419e4fbb87340f5a0f995e605b74c5f6d943e| - |Client ID
(AzureKeyVaultClientId)|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant. |ed4129d9-b913-4514-83db-82e305163bec| - |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers.

Enabling this setting (`true`) blocks attempts in AL to read secrets from another publisher's key vault. When extensions that use key vault secrets are published, you must provide your Azure AD tenant ID.

**Important** We recommend that you only disable this setting If you disable this setting (`false`), the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. For more information, see [App Key Vaults - Security considerations](extension-key-vault.md#security). |true| + |Setting
(key name)|Value| + |--------|-------------------------------| + |Client Certificate Store Location
(AzureKeyVaultClientCertificateStoreLocation)|Set to the certificate store location where key vault certificate was stored.

Example:
LocalMachine| + |Client Certificate Store Name
(AzureKeyVaultClientCertificateStoreName)|Set to the certificate store name where key vault certificate was stored.

Example:
MY| + |Client Certificate Thumbprint
(AzureKeyVaultClientCertificateThumbprint)|Set to the thumbprint for the key vault certificate.

Example:
649419e4fbb87340f5a0f995e605b74c5f6d943e| + |Client ID
(AzureKeyVaultClientId)|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant.

Example:
ed4129d9-b913-4514-83db-82e305163bec| + |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers.

Enabling this setting (`true`) blocks attempts in AL to read secrets from another publisher's key vault. When extensions that use key vault secrets are published, you must provide your Azure AD tenant ID.

**Important** We recommend that you only set this to `false` if you trust all extensions that will be installed. For more information, see [App Key Vaults - Security considerations](extension-key-vault.md#security).

Example:
true| You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). @@ -178,12 +178,11 @@ To complete this task, you'll need the user name of the service account that run At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. - ## Monitoring and Troubleshooting -Extensions +Extensions can be set up to emit telemetry data to Azure Application Insights. The telemetry data provides information about the success or failure provide information about problems with the set up of the App Key Vault. + -The initialization failures provide information about problems with the set up of the App Key Vault. ## See Also From 1b1656c5e240d52cfc9a4bf10696514446ce8598 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 10:11:17 +0200 Subject: [PATCH 076/950] updates --- .../administration/extension-key-vault.md | 49 +---------- .../setup-app-key-vault-onprem.md | 1 - .../administration/telemetry-overview.md | 2 +- dev-itpro/developer/devenv-app-key-vault.md | 85 +++++++++++++++---- dev-itpro/developer/devenv-json-files.md | 3 +- 5 files changed, 75 insertions(+), 65 deletions(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 11f896bd90..3833c3fcef 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -326,55 +326,10 @@ Send an email to TODO@microsoft.com to start the onboarding process. This should The onboarding process involves a manual verification step that verifies that you own the AAD tenant that contains the key vaults. --> -## Security considerations -Keep the following information in mind when you use the App Key Vault feature with your extensions. - -### Mark Methods as NonDebuggable - -When your code works with secrets, whether from a key vault or from Isolated Storage, block the ability to debug relevant methods by using the [NonDebuggable Attribute](../methods/devenv-nondebuggable-attribute.md). It prevents other partners from debugging into your code and seeing the secrets. - -### Don't pass the App Key Vault Secret Provider to untrusted code - -Once the **App Key Vault Secret Provider** codeunit has been initialized, it can be used to get secrets. - -- If you pass the codeunit to another method, then that method is also able use it. -- If you pass the codeunit to a method in another extension, then the other extension can also use the secret provider to get secrets. - -These conditions may not be what you want, so be careful with who you pass the secret provider. - -### Run publisher validation - -For on-premises deployments, you can configure [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the server's **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabledPublisher) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. - -> [!TIP] -> With a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online production environment, publisher validation is not performed for per-tenant extensions. Publisher validation is done automatically for onboarded AppSource extensions. - -#### How it works - -Publisher validation is done by comparing the key vault secret provider's Azure AD tenant ID with the extension publisher's Azure AD tenant ID. It works this way: - -1. When an extension is published by using the [Publish-NAVApp cmdlet](/powershell/module/microsoft.dynamics.nav.apps.management/publish-navapp), the publisher can provide their Azure AD tenant ID by setting the `-PublisherAzureActiveDirectoryTenantId` parameter: - - ```powershell - Publish-NavApp -ServerInstance -Path -PublisherAzureActiveDirectoryTenantId - ``` - - > [!NOTE] - > An error won't occur if `-PublisherAzureActiveDirectoryTenantId` isn't set. There is nothing preventing you from publishing the extension at this point. - -2. When the extension runs, it tries to initialize the **App Key Vault Secret Provider** codeunit. -3. The system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: - - - If they match, initialization succeeds. - - If they don't match, an error occurs. - -#### Turning off publisher validation - -Publisher validation is turned on by default, which is the recommended setting. If it's turned off, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. So, don't turn off publisher validation unless you trust the extensions that can be potentially installed. - -For information about how to turn publisher validation on or off, see [Configuring Business Central Server](configure-server-instance.md). ## See Also +[Security Considerations With App Key Vaults](../developer/devenv-app-key-vault.md#security) +[Monitoring and Troubleshooting App Key Vaults](../developer/devenv-app-key-vault.md#troubleshooting) [Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index 81c17e2a3f..1d99959da3 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -183,7 +183,6 @@ At this point, you can run your extensions that use key vault secrets to read se Extensions can be set up to emit telemetry data to Azure Application Insights. The telemetry data provides information about the success or failure provide information about problems with the set up of the App Key Vault. - ## See Also [Authentication and Credential Types](Users-Credential-Types.md) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index b039bda502..e6766b3b43 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -45,7 +45,7 @@ Sending telemetry data to Application Insights requires you have an Application - For [!INCLUDE[prodshort](../developer/includes/prodshort.md)] On-premises, see [Enable Sending Telemetry to Application Insights](telemetry-enable-application-insights.md). -## Viewing telemetry data in Application Insights +## Viewing telemetry data in Application Insights Telemetry from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is stored in Azure Monitor Logs in the *traces* table. You can view collected data by writing log queries. Log queries are written in the Kusto query language (KQL). For more information, see [Logs in Azure Monitor](/azure/azure-monitor/platform/data-platform-logs) and [Overview of log queries in Azure Monitor](/azure/azure-monitor/log-query/log-query-overview). diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md index aeb76ffa0a..972dd658f3 100644 --- a/dev-itpro/developer/devenv-app-key-vault.md +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -83,37 +83,92 @@ page 50100 HelloWorldPage The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. -## Security considerations +## Security considerations -Keep the following information in mind when you use the App Key Vault feature. +Keep the following information in mind when you use the App Key Vault feature with your extensions. -### Use NonDebuggable +### Mark Methods as NonDebuggable -As always when your code works with secrets, whether from a key vault or from Isolated Storage, remember to mark the methods as NonDebuggable. This prevents other partners from debugging into your code and seeing the secrets. +When your code works with secrets, whether from a key vault or from Isolated Storage, block the ability to debug relevant methods by using the [NonDebuggable Attribute](../methods/devenv-nondebuggable-attribute.md). It prevents other partners from debugging into your code and seeing the secrets. ### Don't pass the App Key Vault Secret Provider to untrusted code -Once the App Key Vault Secret Provider codeunit has been initialized, it can be used to get secrets. If you pass the codeunit to another function, then that function can also use it. If you pass the codeunit to a function in another extension, then the other extension can also use the secret provider to get secrets. This may not be what you want, so be careful with who you pass the secret provider to. +Once the **App Key Vault Secret Provider** codeunit has been initialized, it can be used to get secrets. -### Run with publisher validation +- If you pass the codeunit to another method, then that method is also able use it. +- If you pass the codeunit to a method in another extension, then the other extension can also use the secret provider to get secrets. -In the on-premises steps above, you configured the NST to run with publisher validation disabled. You should only do this if you trust all extensions that get installed to not do malicious things like read secrets they are not supposed to. If you don't trust all extensions that might get installed, you should enable publisher validation. This is how the Business Central SaaS service is configured. +These conditions may not be what you want, so be careful with who you pass the secret provider. -When publisher validation is enabled, and an extension tries to initialize the App Key Vault Secret Provider codeunit, the following check will be performed: +### Run publisher validation -`Extension.KeyVaultUrls.AadTenantId == Extension.PublisherAadTenantId` +For on-premises deployments, you can configure [!INCLUDE[server](../developer/includes/server.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the server's **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabledPublisher) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. -Only if this check is satisfied will the initialization succeed. +> [!TIP] +> With a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online production environment, publisher validation is not performed for per-tenant extensions. Publisher validation is done automatically for onboarded AppSource extensions. -So how does the NST know an extension publisher's AAD tenant ID? The value can be specified when publishing an extension, like this: +#### How it works -Publish-NavApp … -PublisherAzureActiveDirectoryTenantId +Publisher validation is done by comparing the key vault secret provider's Azure AD tenant ID with the extension publisher's Azure AD tenant ID. It works this way: -In SaaS, this value will always be empty for PTEs and dev extensions, and it will only be non-empty for App Source apps if they have been onboarded. +1. When an extension is published by using the [Publish-NAVApp cmdlet](/powershell/module/microsoft.dynamics.nav.apps.management/publish-navapp), the publisher can provide their Azure AD tenant ID by setting the `-PublisherAzureActiveDirectoryTenantId` parameter: -If you don't trust all extensions that might get installed, you should enable publisher validation. The Business Central SaaS service is configured to validate publish + ```powershell + Publish-NavApp -ServerInstance -Path -PublisherAzureActiveDirectoryTenantId + ``` + + > [!NOTE] + > An error won't occur if `-PublisherAzureActiveDirectoryTenantId` isn't set. There is nothing preventing you from publishing the extension at this point. + +2. When the extension runs, it tries to initialize the **App Key Vault Secret Provider** codeunit. +3. The system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: + + - If they match, initialization succeeds. + - If they don't match, an error occurs. + +#### Turning off publisher validation + +Publisher validation is turned on by default, which is the recommended setting. If it's turned off, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. So, don't turn off publisher validation unless you trust the extensions that can be potentially installed. + +For information about how to turn publisher validation on or off, see [Configuring Business Central Server](configure-server-instance.md). + +## Monitoring and troubleshooting + +### Compiling and publishing + +If you get errors when you compile or publish your extension, the most likely reasons are the following: + +- You are using an old Visual Studio Code AL extension. Upgrade to the latest AL extension. + +- Your extension targets an older runtime. Make sure that the `"runtime"` value in the app.json file is at least `"6.0"`. + +- You are running an old version of [!INCLUDE[server](../developer/includes/server.md)]. Use upgrade to at least version 17.0. + +### Runtime + +For runtime operations, there are two sources that you can use for gathering details: + +- Windows Event Log of the machine running the [!INCLUDE[server](../developer/includes/server.md)]. +- Application Insights. + +These sources provide details about retrieving secrets from key vaults, for calls to the `TryInitializeFromCurrentApp` and `GetSecret` methods from an extension. + +#### Using Application Insights + +You can set up extensions to emit telemetry to an Application Insights resource in Azure. + +1. Get Application Insights resource. + + Copy the the reource's instrumentation key +2. In the app.json file of the extension, add the `"applicationInsightsKey"`: + + ``` + "applicationInsightsKey": [""] + ``` +3. Now, you can run your extensions and view data in Application Insights. + + For more information, see [Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) and [Analyzing App Key Vault Secret Trace Telemetry](../administration/telemetry-extension-key-vault-trace.md). -When **false**, the server instance won't do any additional validation to ensure extensions have the right to read secrets from the key vaults that they specify. This condition implies some risk of unauthorized access to key vaults that you should be aware of. ## See Also [Authentication and Credential Types](Users-Credential-Types.md) diff --git a/dev-itpro/developer/devenv-json-files.md b/dev-itpro/developer/devenv-json-files.md index e4081953fb..73c1bbe460 100644 --- a/dev-itpro/developer/devenv-json-files.md +++ b/dev-itpro/developer/devenv-json-files.md @@ -41,7 +41,6 @@ The following table describes the settings in the `app.json` file: |application|Yes, if base application is referenced in the extension|The supported version of the system and base application package file, for example: "16.0.0.0". The file name of this reference is Microsoft_Application.app and the `name` is `Application`. For code-customized base applications, the Microsoft_Application.app file can be modified to reference the code-customized base application instead. It is important to keep `"name": "Application"` in the extension, but information about publisher can be changed and the .app file can be renamed. For more information, see [The Microsoft_Application.app File](devenv-application-app-file.md).| |idRange|Yes|For example: `"idRange": {"from": 50100,"to": 50149}`. A range for application object IDs. For all objects outside the range, a compilation error will be raised. When you create new objects, an ID is automatically suggested.| |idRanges|Yes|For example: `"idRanges": [{"from": 50100,"to": 50200},{"from": 50202,"to": 50300}]`. A list of ranges for application object IDs. For all objects outside the ranges, a compilation error will be raised. When you create new objects, an ID is automatically suggested. You must use *either* the `idRange` *or* the `idRanges` setting. Overlapping ranges are not allowed and will result in a compilation error. | -|keyVaultUrls|No|List of URLs of key vaults that the extension from which the extension can retrieve secrets. For example: `"keyVaultUrls": [ "https://myfirstkeyvault.vault.azure.net", "https://mysecondkeyvault.vault.azure.net" ]`.

For more information, see [App Key Vaults](../administration/extension-key-vault.md). |showMyCode|No|This is by default set to `false` and not visible in the manifest. To enable viewing the source code when debugging into an extension, add the following setting: `"showMyCode": true`| |target|No|By default this is `Cloud`. The setting currently has the following options: `Internal`, `Extension`, `OnPrem`, and `Cloud`. The `Internal` and `Extension` settings are being deprecated with runtime 4.0 and replaced by the `OnPrem` and `Cloud` respectively. For on-premises, you can set this to `OnPrem` to get access to otherwise restricted APIs and .NET Interop. The Business Central Server setting must then also be set to `OnPrem`. **Note:** System tables that have the [Scope](properties/devenv-scope-property.md) property set to `Internal`/`OnPrem` cannot be accessed from extensions that have `target` set to `Cloud`/`External` through direct reference or through RecordRef. For more information, see [Compilation Scope Overview](devenv-compilation-scope-overview.md)| |contextSensitiveHelpUrl|No, but required for AppSource submission|The URL for the website that displays context-sensitive Help for the objects in the app, such as `https://mysite.com/documentation/`. If the app does not support all locales currently supported by [!INCLUDE [prodshort](includes/prodshort.md)], then include a parameter for the locale in this URL, `/{0}/`, and also specify the relevant locales in the `supportedLocales` setting.| @@ -51,6 +50,8 @@ The following table describes the settings in the `app.json` file: |features|No|Specifies a list of options for translations. The `TranslationFile` option generates a `\Translations` folder that is populated with the .xlf file that contains all the labels, label properties, and report labels that you are using in the extension. The `GenerateCaptions` option depends on the `TranslationFile` setting. It generates captions for objects that do not have a `Caption` or `CaptionML` specified, these are then written to the .xlf file.
The syntax is `"features": [ "TranslationFile", "GenerateCaptions" ]`. For more information, see [Working with Translation Files](devenv-work-with-translation-files.md)| |internalsVisibleTo|No|Specifies a list of modules that have access to the objects that are marked as `Internal` using the **Access** property from the current module.
The syntax is `{ "appId": "d6c3f231-08d3-4681-996f-261c06500e1a", "name": "TheConsumer", "publisher": "Microsoft"}]`. For more information see [Access Property](properties/devenv-access-property.md) and [InternalEvent Attribute](methods/devenv-internal-attribute.md).| |propagateDependencies|No|Specifies whether the dependencies of this project should be propagated as direct dependencies of projects that depend on this one. Default is `false`. If set to `true` then any dependencies of the current package will be visible to consumers of the package. For example, if A depends on B that depends on C, by default, A will not be able to use types defined in C. If B has `"propagateDependencies" : "true"`, then A will be able to use types defined in C without taking a direct dependency.
**Note:** `propagateDependencies` applies to all dependencies, there is no option to exclude specific dependencies.| +|applicationInsightsKey|The instrumentation key of the Azure Application Insights resource for monitoring app secrets retrieval by extensions.

For more information, see [App Key Vaults](../administration/extension-key-vault.md)| +|keyVaultUrls|No|List of URLs of key vaults that the extension from which the extension can retrieve secrets. For example: `"keyVaultUrls": [ "https://myfirstkeyvault.vault.azure.net", "https://mysecondkeyvault.vault.azure.net" ]`.

For more information, see [App Key Vaults](../administration/extension-key-vault.md). ## Launch.json file From a2320831187a298b8ed55da7220962ba433917b5 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 10:18:42 +0200 Subject: [PATCH 077/950] Update devenv-app-key-vault.md --- dev-itpro/developer/devenv-app-key-vault.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md index 972dd658f3..5b2bf02305 100644 --- a/dev-itpro/developer/devenv-app-key-vault.md +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -157,9 +157,12 @@ These sources provide details about retrieving secrets from key vaults, for call You can set up extensions to emit telemetry to an Application Insights resource in Azure. -1. Get Application Insights resource. +1. Create an Application Insights resource in Azure if you don't have one. + + The Application Insights resource will be assigned an instrumentation key. Copy this key because you'll need it to enable Application Insights in the [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)]. + + For more information, see [Create an Application Insights resource](/azure/azure-monitor/app/create-new-resource). - Copy the the reource's instrumentation key 2. In the app.json file of the extension, add the `"applicationInsightsKey"`: ``` From 399224ee040d194798e7a59da266151b2aa49035 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 10:30:14 +0200 Subject: [PATCH 078/950] fix --- .../setup-app-key-vault-onprem.md | 32 +++++++------------ .../administration/setup-app-key-vault.md | 4 +-- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index 1d99959da3..06ad4c8d02 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -26,17 +26,11 @@ For more information about developing extensions and key vaults, see [Using App As part of the setup later on, you'll have to register and configure an application in Azure AD for reading key vaults, which requires the use of a certificate. The certificate is used to prove the application's identity when requesting upon request. In a production environment, obtain a certificate from a certification authority or trusted provider. - In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. For example, on your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer, start Windows PowerShell as an administrator. Then at the prompt, run the following commands, one at a time: + In a test environment, if you don't have a certificate, then you can create your own self-signed certificate. For example, on your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer, start Windows PowerShell as an administrator. Then at the prompt, run the following commands: ```powershell $cert = New-SelfSignedCertificate -Subject "BusinessCentralKeyVaultReader" -Provider "Microsoft Strong Cryptographic Provider" - ``` - - ```powershell $cert.Thumbprint - ``` - - ```powershell Export-Certificate -Cert $cert -FilePath c:\certs\BusinessCentralKeyVaultReader.cer ``` @@ -44,7 +38,7 @@ For more information about developing extensions and key vaults, see [Using App ## Create the Azure Key Vault with secrets -Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. +Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. An extension can be set up with one or two key vaults. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. -At this point, you can run your extensions that use key vault secrets to read secrets from key vault. For troubleshooting, please look in the Event Log and configure App Insights telemetry. - -## Monitoring and Troubleshooting - -Extensions can be set up to emit telemetry data to Azure Application Insights. The telemetry data provides information about the success or failure provide information about problems with the set up of the App Key Vault. - +At this point, you can run your extensions that use key vault secrets to read secrets from key vault. ## See Also - +[Security Considerations With App Key Vaults](../developer/devenv-app-key-vault.md#security) +[Monitoring and Troubleshooting App Key Vaults](../developer/devenv-app-key-vault.md#troubleshooting) [Authentication and Credential Types](Users-Credential-Types.md) [Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file diff --git a/dev-itpro/administration/setup-app-key-vault.md b/dev-itpro/administration/setup-app-key-vault.md index 8602a9f31a..54ceeef9b8 100644 --- a/dev-itpro/administration/setup-app-key-vault.md +++ b/dev-itpro/administration/setup-app-key-vault.md @@ -87,6 +87,6 @@ The onboarding process involves a manual verification step that verifies that yo ## See Also -[Authentication and Credential Types](Users-Credential-Types.md) -[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) +[Security Considerations With App Key Vaults](../developer/devenv-app-key-vault.md#security) +[Monitoring and Troubleshooting App Key Vaults](../developer/devenv-app-key-vault.md#troubleshooting) [Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file From c516d09b328f7b2629c074cfa940b6eb4c8dd525 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 10:32:26 +0200 Subject: [PATCH 079/950] Update extension-key-vault.md --- dev-itpro/administration/extension-key-vault.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/administration/extension-key-vault.md b/dev-itpro/administration/extension-key-vault.md index 3833c3fcef..042eace59d 100644 --- a/dev-itpro/administration/extension-key-vault.md +++ b/dev-itpro/administration/extension-key-vault.md @@ -31,7 +31,7 @@ An extension can retrieve secrets from one or two different Azure Key Vaults. Th Once you have an Azure Key Vault, you can develop [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions to retrieve secrets from the key vault. In short, this work involves specifying the key vault's URL and adding code to retrieve a secret from the key vault. -For more information, see [Using App Key Vaults with Extensions](developer/devenv-app-key-vault.md). +For more information, see [Using App Key Vault Secrets in Extensions](../developer/devenv-app-key-vault.md). When completed, the **Overview** displays in the portal for the new application. - Copt the **Display name** and/or **Application (client) ID**. You will use this information later. + Copy the **Application (client) ID**. You'll use this information later. 2. Upload the security certificate to the registered application. In this step, you upload the certificate file that you obtained as part of the prerequisites. - From the key vault reader application overview page, select **Certificates & secrets**, **Upload certificate**, and follow instructions to locate and upload the certificate. + Go to the key vault reader application overview page. Select **Certificates & secrets** > **Upload certificate**. Follow the instructions to locate and upload the certificate. ## Grant the key vault reader application permission to key vaults In this task, you grant the key vault reader application permission to read secrets from your key vaults. -The steps in this task are done from the the [Azure portal](https://portal.azure.com). +The steps in this task are done from the [Azure portal](https://portal.azure.com). 1. Open the key vault in the portal. 2. Select **Access policies**, then **Add Access Policy**. 3. Set **Secret Permissions** to **Get**. -4. Select **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. +4. Choose **Select principal**, and on the right, search for either **Application (client) ID** or display name for the key vault reader application. 5. Select **Add**. 6. Select **Save**. @@ -112,7 +114,7 @@ Next, you configure the [!INCLUDE[server](../developer/includes/server.md)] inst To complete this task, you'll need the user name of the service account that runs the [!INCLUDE[server](../developer/includes/server.md)]. -1. If not already done, import your key vault certificate to the local certificate store for your [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. +1. If not already done, import your key vault certificate to the local certificate store for the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. @@ -142,7 +144,7 @@ To complete this task, you'll need the user name of the service account that run 4. Configure the [!INCLUDE[server](../developer/includes/server.md)] instance. - Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure to enable Azure key vault on the server instance: + Now, you'll configure App Key Vault settings on the server instance. The following table describes the settings that you must configure: |Setting
(key name)|Value| |--------|-------------------------------| @@ -150,11 +152,11 @@ To complete this task, you'll need the user name of the service account that run |Client Certificate Store Name
(AzureKeyVaultClientCertificateStoreName)|Set to the certificate store name where key vault certificate was stored.

Example:
MY| |Client Certificate Thumbprint
(AzureKeyVaultClientCertificateThumbprint)|Set to the thumbprint for the key vault certificate.

Example:
649419e4fbb87340f5a0f995e605b74c5f6d943e| |Client ID
(AzureKeyVaultClientId)|Set to the **Application (client) ID** of the key vault reader application registered in your Azure AD tenant.

Example:
ed4129d9-b913-4514-83db-82e305163bec| - |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers.

Enabling this setting (`true`) blocks attempts in AL to read secrets from another publisher's key vault. When extensions that use key vault secrets are published, you must provide your Azure AD tenant ID.

**Important** We recommend that you only set this to `false` if you trust all extensions that will be installed. For more information, see [App Key Vaults - Security considerations](extension-key-vault.md#security).

Example:
true| + |Enable Publisher Validation
(AzureKeyVaultAppSecretsPublisherValidationEnabled)|Specifies whether extensions can only use key vaults that belong to their publishers.

Enabling this setting (`true`) blocks attempts in AL to read secrets from another publisher's key vault. When extensions that use key vault secrets are published, you must provide your Azure AD tenant ID.

**Important** We recommend that you only set it to `false` if you trust all extensions that will be installed. For more information, see [App Key Vaults - Security considerations](devenv-app-key-vault-overview.md#security).

Example:
true| You can configure the instance using the [[!INCLUDE[admintool](../developer/includes/admintool.md)]](administration-tool.md) or [Set-NAVServerConfiguration cmdlet](https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.management/set-navserverconfiguration). - For example, to use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Substitute brackets with your own values. + To use the Set-NAVServerConfiguration cmdlet, start the [[!INCLUDE[admintool](../developer/includes/admintool.md)] as an administrator, and run the following commands one at a time. Replace brackets with your own values. ```powershell Set-NAVServerConfiguration -ServerInstance -KeyName AzureKeyVaultClientCertificateStoreLocation -KeyValue diff --git a/dev-itpro/administration/setup-app-key-vault.md b/dev-itpro/administration/setup-app-key-vault.md index 54ceeef9b8..e0c1c538bb 100644 --- a/dev-itpro/administration/setup-app-key-vault.md +++ b/dev-itpro/administration/setup-app-key-vault.md @@ -16,7 +16,7 @@ In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vaul ## Create the Azure Key Vault with secrets -Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. +In this task, you create a key vault in Azure, and add the secrets that you want to make available to your extensions. An extension can use up to two key vaults, so you can create more than one. + +## App Key Vault initialization failed + +Occurs when a key vault failed to be initialized. + +### General dimensions + +|Dimension|Description or value| +|---------|-----| +|message|**App Key Vault initialization failed.**| +|severityLevel|**3**| + +### Custom dimensions + +|Dimension|Description or value| +|---------|-----| +|aadTenantId|Specifies that Azure Active Directory (Azure AD) tenant ID used for Azure AD authentication. For on-premises, if you aren't using Azure AD authentication, this value is **common**. | +|alObjectId|Specifies the ID of the AL object that was run by request.| +|alObjectName|Specifies the name of the AL object that was run by request.| +|alObjectType|Specifies the type of AL object that was run by request.| +|alStackTrace|The stack trace in AL.| +|clientType|Specifies the type of client that executed request, such as **Background** or **Web**. For a list of the client types, see [ClientType Option Type](../developer/methods-auto/clienttype/clienttype-option.md).| +|companyName|The display name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] company that was used at time of execution. || +|component|**Dynamics 365 Business Central Server**.| +|componentVersion|Specifies the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] version number.| +|deprecatedKeys|A comma-separated list of all the keys that have been deprecated. The keys in this list are still supported but will eventually be removed in the next major release. We recommend that update any queries that use these keys to use the new key name.| +|environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| +|environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| +|eventId|**RT0015**| +|extensionId|Specifies the AppID of the extension that requested the secret.| +|extensionPublisher|Specifies the publisher of the extension that requested the secret. | +|extensionVersion|Specifies the version of the extension that requested the secret.| +|failureReason|Specifies the error that occurred.| +|telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| + + + +## App Key Vault secret retrieval succeeded + +Occurs when a secret used by an extension is successfully retrieved from an Azure Key Vault. + +### General dimensions + +|Dimension|Description or value| +|---------|-----| +|message|**App Key Vault secret retrieval succeeded from key vault '{keyVaultUri}'.**| +|severityLevel|**1**| + +### Custom dimensions + +|Dimension|Description or value| +|---------|-----| +|aadTenantId|Specifies that Azure Active Directory (Azure AD) tenant ID used for Azure AD authentication. For on-premises, if you aren't using Azure AD authentication, this value is **common**. | +|alObjectId|Specifies the ID of the AL object that was run by request.| +|alObjectName|Specifies the name of the AL object that was run by request.| +|alObjectType|Specifies the type of AL object that was run by request.| +|alStackTrace|The stack trace in AL.| +|clientType|Specifies the type of client that executed the SQL Statement, such as **Background** or **Web**. For a list of the client types, see [ClientType Option Type](../developer/methods-auto/clienttype/clienttype-option.md).| +|companyName|The display name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] company that was used at time of execution. || +|component|**Dynamics 365 Business Central Server**.| +|componentVersion|Specifies the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] version number.| +|deprecatedKeys|A comma-separated list of all the keys that have been deprecated. The keys in this list are still supported but will eventually be removed in the next major release. We recommend that update any queries that use these keys to use the new key name.| +|environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| +|environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| +|eventId|**RT0016**| +|extensionId|Specifies the AppID of the extension that requested the secret.| +|extensionPublisher|Specifies the publisher of the extension that requested the secret. | +|extensionVersion|Specifies the version of the extension that requested the secret.| +|keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| +|telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| + + + +## App Key Vault secret retrieval failed + +Occurs when an extension failed to retrieve a secret from a specified Azure key vault. + +### General dimensions + +|Dimension|Description or value| +|---------|-----| +|message|**App Key Vault secret retrieval failed from key vault '{keyVaultUri}'.**| +|severityLevel|**3**| + +### Custom dimensions + +|Dimension|Description or value| +|---------|-----| +|aadTenantId|Specifies that Azure Active Directory (Azure AD) tenant ID used for Azure AD authentication. For on-premises, if you aren't using Azure AD authentication, this value is **common**. | +|alObjectId|Specifies the ID of the AL object that was run by request.| +|alObjectName|Specifies the name of the AL object that was run by request.| +|alObjectType|Specifies the type of AL object that was run by request.| +|alStackTrace|The stack trace in AL.| +|clientType|Specifies the type of client that executed the SQL Statement, such as **Background** or **Web**. For a list of the client types, see [ClientType Option Type](../developer/methods-auto/clienttype/clienttype-option.md).| +|companyName|The display name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] company that was used at time of execution. || +|component|**Dynamics 365 Business Central Server**.| +|componentVersion|Specifies the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] version number.| +|deprecatedKeys|A comma-separated list of all the keys that have been deprecated. The keys in this list are still supported but will eventually be removed in the next major release. We recommend that update any queries that use these keys to use the new key name.| +|environmentName|Specifies the name of the tenant environment. See [Managing Environments](tenant-admin-center-environments.md).| +|environmentType|Specifies the environment type for the tenant, such as **Production**, **Sandbox**, **Trial**. See [Environment Types](tenant-admin-center-environments.md#types-of-environments)| +|eventId|**RT0017**| +|extensionId|Specifies the AppID of the extension that requested the secret.| +|extensionPublisher|Specifies the publisher of the extension that requested the secret. | +|extensionVersion|Specifies the version of the extension that requested the secret.| +|keyVaultUri|Specifies the DNS name of the Azure key vault that was used in the request. The keyVaultUris are specified in the [app.json](../developer/devenv-json-files.md) file of the extension.| +|telemetrySchemaVersion|Specifies the version of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] telemetry schema.| + +### Troubleshooting failures + + + +## See also + +[App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](../developer/devenv-app-key-vault.md) +[Monitoring and Analyzing Telemetry](telemetry-overview.md) +[Enabling Application Insights for Tenant Telemetry On-Premises](telemetry-enable-application-insights.md) +[Enable Sending Telemetry to Application Insights](tenant-admin-center-telemetry.md#appinsights) diff --git a/dev-itpro/administration/telemetry-event-ids.md b/dev-itpro/administration/telemetry-event-ids.md index b5f510d5ac..06e252179e 100644 --- a/dev-itpro/administration/telemetry-event-ids.md +++ b/dev-itpro/administration/telemetry-event-ids.md @@ -31,10 +31,10 @@ The following tables list the IDs of [!INCLUDE[prodshort](../developer/includes/ |RT0010|Extension lifecycle|[Extension Update Failed: exception raised in extension {extensionName} by {extensionPublisher} (updating to version {extensionTargetedVersion})](telemetry-extension-update-trace.md#extension-update-failed-exception-raised-in-extension) | | RT0012 | Performance | [Database lock timed out](telemetry-database-locks-trace.md#database-lock-timed-out) | | RT0013 | Performance | [Database lock snapshot: {snapshotId}](telemetry-database-locks-trace.md#database-lock-snapshot) | -| RT0014 | Security | [App Key Vault initialization succeeded: '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#initializedsuccess) | -| RT0015 | Security | [App Key Vault initialization failed](telemetry-extension-key-vault-trace.md#initializedfailed) | -| RT0016 | Security | [App Key Vault secret retrieval succeeded from key vault '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#retrievedsuccess) | -| RT0017 | Security | [App Key Vault secret retrieval failed from key vault: '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#retrievedfailed) | +| RT0014 | Security | [App Key Vault initialization succeeded: '{keyVaultUri}'](telemetry-app-key-vault-trace.md#initializedsuccess) | +| RT0015 | Security | [App Key Vault initialization failed](telemetry-app-key-vault-trace.md#initializedfailed) | +| RT0016 | Security | [App Key Vault secret retrieval succeeded from key vault '{keyVaultUri}'](telemetry-app-key-vault-trace.md#retrievedsuccess) | +| RT0017 | Security | [App Key Vault secret retrieval failed from key vault: '{keyVaultUri}'](telemetry-app-key-vault-trace.md#retrievedfailed) | ## Lifecycle events diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md index 31d7362447..2b0fc3ed03 100644 --- a/dev-itpro/administration/telemetry-extension-key-vault-trace.md +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -15,7 +15,7 @@ ms.author: jswymer **INTRODUCED IN:** Business Central 2020 release wave 2 -App key vault telemetry gathers information about the acquisition of secrets in Azure Key Vaults by extensions at runtime. Secrets are a kind of credential used for authenticating an extension. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). +App key vault telemetry gathers information about the acquisition of secrets in Azure Key Vaults by extensions at runtime. Secrets are a kind of credential used for authenticating an extension. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](devenv-app-key-vault-overview.md). The app key vault secret process has two operations: *initialization* and *retrieval*. The telemetry data provides information about the success or failure for each of these operations. There are various conditions that cause a failure. The failure messages provide insight into the cause of the failure, helping you identify, troubleshoot, and resolve issues. @@ -35,7 +35,7 @@ Retrieval is the second stage, and occurs after a successful initialization. In - The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. - The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. -For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](extension-key-vault.md). +For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](devenv-app-key-vault-overview.md). ## App Key Vault secret initialization succeeded diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index e6766b3b43..2a7636a797 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -26,7 +26,7 @@ In Application Insights, telemetry from [!INCLUDE[prodshort](../developer/includ |Area | Description |Online/On-premises|See more| |----------|-------------|-----------------|--------| -|App Key Vault secrets |Provides information about the retrieval of secrets from Azure Key Vaults by extensions.|Both|[Analyzing App Key Vault Secret Trace Telemetry](telemetry-extension-key-vault-trace.md) | +|App Key Vault secrets |Provides information about the retrieval of secrets from Azure Key Vaults by extensions.|Both|[Analyzing App Key Vault Secret Trace Telemetry](telemetry-app-key-vault-trace.md) | |Authorization|Provides information about user sign-in attempts. Information includes success or failure indication, reason for failure, user type, and more.|Online|[Analyzing Authentication Telemetry](telemetry-authorization-trace.md) | |Company lifecycle|Provides information about creating, copying, and deleting of companies.|Both|[Analyzing Company Lifecycle Telemetry](telemetry-company-lifecycle-trace.md) | |Database lock timeouts|Provides information about database locks that have timed out. |Both|[Database Lock Timeout Telemetry](telemetry-database-locks-trace.md)| diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md index 5b2bf02305..3c9587942e 100644 --- a/dev-itpro/developer/devenv-app-key-vault.md +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -12,20 +12,18 @@ author: jswymer --- # Using Key Vault Secrets in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions -This article describes how to code an extension to retrieve secrets from Azure Key Vaults. Secrets are a kind of credential used for authenticating en extension. Secrets are typically used when the extensions makes calls to web service. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](../administration/extension-key-vault.md). +This article describes how to code an extension to retrieve secrets from Azure Key Vaults. Secrets are a kind of credential used for authenticating en extension. Secrets are typically used when the extensions calls a web service. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](../devenv-app-key-vault-overview.md). -Developing an extension to use secrets from a key vaults involves two tasks, as described in this article: +Developing an extension to use secrets from a key vault involves two tasks, as described in this article: - Specifying the Azure Key Vault in the extension's manifest. - Adding code to retrieve the secrets from the key vault. -Secrets are actually retrieved at runtime. - ## Preparation -Using secrets requires that you have at least one Azure Key Vault with secrets set up and configured for use by the the service. For more information, see [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) or [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises ](setup-app-key-vault-onprem.md). +- Using secrets requires that you have at least one Azure Key Vault with secrets set up and configured for use by the service. If you don't already have an Azure Key Vault, see [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) or [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises](setup-app-key-vault-onprem.md). -For coding, you'll need the URI the Azure Key Vault that stores the secret and the name of the secret itself. If you don't have this information, you can get it from Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal). +- For coding, you'll need the URI the Azure Key Vault that stores the secret and the name of the secret itself. If you don't have this information, you can get it from Azure portal. For instructions, see [Quickstart: Set and retrieve a secret from Azure Key Vault using the Azure portal](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal). ## Specify the Azure Key Vault in extensions @@ -51,7 +49,7 @@ Specifying two key vaults ensures a higher availability of secrets. At runtime, ## Add code to retrieve secrets the key vault -Next, you add code to the extension for reading secrets from the key vault at runtime. To read secrets, you use the **Secrets** module of the System Application, specifically codeunit **3800 "App Key Vault Secret Provider"**. This codeunit includes two methods: +Next, you add code to the extension for reading secrets from the key vault at runtime. To read secrets, you use the **Secrets** module of the System Application. Specifically, you'll use codeunit **3800 "App Key Vault Secret Provider"**. This codeunit includes two methods: | Method |Description| |--------|-----------| @@ -136,13 +134,13 @@ For information about how to turn publisher validation on or off, see [Configuri ### Compiling and publishing -If you get errors when you compile or publish your extension, the most likely reasons are the following: +If you get errors when you compile or publish your extension, the most likely reasons are: -- You are using an old Visual Studio Code AL extension. Upgrade to the latest AL extension. +- You're using an old Visual Studio Code AL extension. Upgrade to the latest AL extension. - Your extension targets an older runtime. Make sure that the `"runtime"` value in the app.json file is at least `"6.0"`. -- You are running an old version of [!INCLUDE[server](../developer/includes/server.md)]. Use upgrade to at least version 17.0. +- You're running an old version of [!INCLUDE[server](../developer/includes/server.md)]. Upgrade to at least version 17.0. ### Runtime @@ -170,10 +168,9 @@ You can set up extensions to emit telemetry to an Application Insights resource ``` 3. Now, you can run your extensions and view data in Application Insights. - For more information, see [Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) and [Analyzing App Key Vault Secret Trace Telemetry](../administration/telemetry-extension-key-vault-trace.md). + For more information, see [Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) and [Analyzing App Key Vault Secret Trace Telemetry](../administration/telemetry-app-key-vault-trace.md). ## See Also - -[Authentication and Credential Types](Users-Credential-Types.md) -[Troubleshooting: The SAML2 token is not valid because its validity period has ended](troubleshooting-SAML2-token-not-valid-because-validity-period-ended.md) -[Configuring Business Central Server](configure-server-instance.md) \ No newline at end of file +[Getting Started with AL](devenv-get-started.md) +[Publishing and Installing Extensions](devenv-how-publish-and-install-an-extension-v2.md) +[Configuring Business Central Server](../administration/configure-server-instance.md) \ No newline at end of file diff --git a/dev-itpro/developer/devenv-json-files.md b/dev-itpro/developer/devenv-json-files.md index 73c1bbe460..12a00f7bbd 100644 --- a/dev-itpro/developer/devenv-json-files.md +++ b/dev-itpro/developer/devenv-json-files.md @@ -50,8 +50,8 @@ The following table describes the settings in the `app.json` file: |features|No|Specifies a list of options for translations. The `TranslationFile` option generates a `\Translations` folder that is populated with the .xlf file that contains all the labels, label properties, and report labels that you are using in the extension. The `GenerateCaptions` option depends on the `TranslationFile` setting. It generates captions for objects that do not have a `Caption` or `CaptionML` specified, these are then written to the .xlf file.
The syntax is `"features": [ "TranslationFile", "GenerateCaptions" ]`. For more information, see [Working with Translation Files](devenv-work-with-translation-files.md)| |internalsVisibleTo|No|Specifies a list of modules that have access to the objects that are marked as `Internal` using the **Access** property from the current module.
The syntax is `{ "appId": "d6c3f231-08d3-4681-996f-261c06500e1a", "name": "TheConsumer", "publisher": "Microsoft"}]`. For more information see [Access Property](properties/devenv-access-property.md) and [InternalEvent Attribute](methods/devenv-internal-attribute.md).| |propagateDependencies|No|Specifies whether the dependencies of this project should be propagated as direct dependencies of projects that depend on this one. Default is `false`. If set to `true` then any dependencies of the current package will be visible to consumers of the package. For example, if A depends on B that depends on C, by default, A will not be able to use types defined in C. If B has `"propagateDependencies" : "true"`, then A will be able to use types defined in C without taking a direct dependency.
**Note:** `propagateDependencies` applies to all dependencies, there is no option to exclude specific dependencies.| -|applicationInsightsKey|The instrumentation key of the Azure Application Insights resource for monitoring app secrets retrieval by extensions.

For more information, see [App Key Vaults](../administration/extension-key-vault.md)| -|keyVaultUrls|No|List of URLs of key vaults that the extension from which the extension can retrieve secrets. For example: `"keyVaultUrls": [ "https://myfirstkeyvault.vault.azure.net", "https://mysecondkeyvault.vault.azure.net" ]`.

For more information, see [App Key Vaults](../administration/extension-key-vault.md). +|applicationInsightsKey|The instrumentation key of the Azure Application Insights resource for monitoring app secrets retrieval by extensions.

For more information, see [App Key Vaults](../devenv-app-key-vault-overview.md)| +|keyVaultUrls|No|List of URLs of key vaults that the extension from which the extension can retrieve secrets. For example: `"keyVaultUrls": [ "https://myfirstkeyvault.vault.azure.net", "https://mysecondkeyvault.vault.azure.net" ]`.

For more information, see [App Key Vaults](../devenv-app-key-vault-overview.md). ## Launch.json file From 47d3a874a72fdf053c047422e265237392b00adf Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 11:22:51 +0200 Subject: [PATCH 081/950] moved --- .../devenv-app-key-vault-overview.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dev-itpro/{administration => developer}/devenv-app-key-vault-overview.md (100%) diff --git a/dev-itpro/administration/devenv-app-key-vault-overview.md b/dev-itpro/developer/devenv-app-key-vault-overview.md similarity index 100% rename from dev-itpro/administration/devenv-app-key-vault-overview.md rename to dev-itpro/developer/devenv-app-key-vault-overview.md From 848de1b759d08070cd2836d80ecfcecd27df1809 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 11:24:45 +0200 Subject: [PATCH 082/950] Update TOC.md --- dev-itpro/TOC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 59fc7d8721..9091434ddf 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -213,9 +213,9 @@ ## [Task Scheduler](developer/devenv-task-scheduler.md) ## App Key Vaults for Secrets ### [Overview](developer/devenv-app-key-vault-overview.md) -### [Using Key Vault Secrets in Extensions](developer/devenv-app-key-vault.md) ### [Setting up App Key Vaults for Online](administration/setup-app-key-vault.md) ### [Setting up App Key Vaults for On-premises](administration/setup-app-key-vault-onprem.md) +### [Using Key Vault Secrets in Extensions](developer/devenv-app-key-vault.md) ## Tables ### [Tables Overview](developer/devenv-tables-overview.md) ### [Table Object](developer/devenv-table-object.md) From 6418edecfdf6cea6d5230b4185ced2fe5dd9b87b Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 9 Jul 2020 11:30:35 +0200 Subject: [PATCH 083/950] fix --- dev-itpro/administration/setup-app-key-vault-onprem.md | 4 ++-- dev-itpro/developer/devenv-app-key-vault.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index 096cac8099..48f28b12a4 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -116,9 +116,9 @@ To complete this task, you'll need the user name of the service account that run 1. If not already done, import your key vault certificate to the local certificate store for the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] server computer. - 1. You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. + You can import the certificate either using the [MMC snap-in](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) or [Import-Certificate cmdlet](/powershell/module/pkiclient/import-certificate) from a Windows PowerShell prompt. - For example, the following PowerShell command installs a certificate to the local machine's personal store: + For example, the following PowerShell command installs a certificate to the local machine's personal store: ```powershell Import-Certificate -FilePath "C:\certificates\BusinessCentralKeyVaultReader.cer" -CertStoreLocation Cert:\LocalMachine\My diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md index 3c9587942e..bd2d6a20ec 100644 --- a/dev-itpro/developer/devenv-app-key-vault.md +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -79,13 +79,13 @@ page 50100 HelloWorldPage } ``` -The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, you can call the `GetSecret` method to read secrets from the key vault. +The call to the `TryInitializeFromCurrentApp` method determines the extension that is currently being executed, then determines the extension's key vaults as specified in the extension manifest. After initialization, the `GetSecret` call reads secrets from the key vault. ## Security considerations Keep the following information in mind when you use the App Key Vault feature with your extensions. -### Mark Methods as NonDebuggable +### Mark methods as NonDebuggable When your code works with secrets, whether from a key vault or from Isolated Storage, block the ability to debug relevant methods by using the [NonDebuggable Attribute](../methods/devenv-nondebuggable-attribute.md). It prevents other partners from debugging into your code and seeing the secrets. From 200f6171ac45285a005286aa2e13bf10cf8e5943 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 16 Jul 2020 10:21:03 +0200 Subject: [PATCH 084/950] Update devenv-method-attributes.md --- dev-itpro/developer/methods/devenv-method-attributes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-itpro/developer/methods/devenv-method-attributes.md b/dev-itpro/developer/methods/devenv-method-attributes.md index e9003ed13b..4c874cfc82 100644 --- a/dev-itpro/developer/methods/devenv-method-attributes.md +++ b/dev-itpro/developer/methods/devenv-method-attributes.md @@ -30,6 +30,7 @@ For example, the Integration attribute has two arguments, and the syntax is: The following method attributes are available: +- [CommitBehavior Attribute](devenv-commitbehavior-attribute.md) - [Business Attribute](devenv-business-attribute.md) - [ConfirmHandler Attribute](devenv-confirmhandler-attribute.md) - [EventSubscriber Attribute](devenv-eventsubscriber-attribute.md) From 78240b1bd97d12bae00a2ffa9f01672bbf7ed1dc Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 16 Jul 2020 10:23:46 +0200 Subject: [PATCH 085/950] Create devenv-commitbehavior-attribute.md --- .../devenv-commitbehavior-attribute.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 dev-itpro/developer/methods/devenv-commitbehavior-attribute.md diff --git a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md new file mode 100644 index 0000000000..9b84b0b1a9 --- /dev/null +++ b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md @@ -0,0 +1,36 @@ +--- +title: "CommitBehavior Attribute" +ms.author: solsen +ms.custom: na +ms.date: 07/16/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: SusanneWindfeldPedersen +--- + +# CommitBehavior Attribute + +Specifies that a method ... + +## Syntax + +``` +[CommitBehavior(CommitBehavior::Ignore)] +local procedure MyEventPublisher() +begin +end; +``` + +## Example + +``` + + +``` + +## See Also + +[AL Method Reference](../methods-auto/library.md) From 25e05a0eaab83f9ecc8dcfd2ced0ffc3bdccad68 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 16 Jul 2020 13:17:58 +0200 Subject: [PATCH 086/950] Update devenv-commitbehavior-attribute.md --- .../devenv-commitbehavior-attribute.md | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md index 9b84b0b1a9..ddd5cf23ad 100644 --- a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md +++ b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md @@ -13,22 +13,67 @@ author: SusanneWindfeldPedersen # CommitBehavior Attribute -Specifies that a method ... +Specifies the behavior of `commit` calls inside the method scope of the call. ## Syntax ``` [CommitBehavior(CommitBehavior::Ignore)] -local procedure MyEventPublisher() +local procedure ProcedureIgnoreCommit() begin + // Do something end; ``` + +## Values + +`CommitBehavior::Ignore` +This will ignore all `commit` calls until the method scope ends. + +`CommitBehavior::Error` +This will throw an exception and stop the execution of further code when a `commit` is called before the end of the scope of the method. + +Note: We can only assign a more restrictive Commit Behavior. That is, if CommitBehavior::Ignore is attempted on a method scope, but the method calling the current method (let’s call it the parent method) is actually running with CommitBehavior::Error, then the current method will continue running with CommitBehavior::Error, even though Ignore attribute was specified. + +The CommitBehavior only lasts for the method scope. +Regardless of whether the method finishes successfully or if an error causes the method to exit prematurely, the CommitBehavior reverts to the standard behavior, where COMMIT statements will commit to the database. + + ## Example ``` +codeunit 50100 MyCodeunit +{ + trigger OnRun() + var + begin + FunctionAllowCommit(); + end; + + local procedure FunctionAllowCommit() + begin + FunctionIgnoreCommit(); + COMMIT; // This is valid, and Commit call will be executed. + end; + + [CommitBehavior(CommitBehavior::Ignore)] + local procedure FunctionIgnoreCommit() + begin + TryFunctionErrorCommit(); + COMMIT; // This call will be silently ignored. + end; + [CommitBehavior(CommitBehavior::Error)] + [TryFunction] + local procedure TryFunctionErrorCommit() + begin + COMMIT; // This will throw an error. No further code will be executed and User will see a dialog to contact the System administrator. + end; + var + myInt: Integer; +} ``` ## See Also From 9546413bd4d6501064bcd2d25954449e1cb61522 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 16 Jul 2020 13:21:00 +0200 Subject: [PATCH 087/950] Update devenv-commitbehavior-attribute.md --- .../methods/devenv-commitbehavior-attribute.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md index ddd5cf23ad..d745cdeb17 100644 --- a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md +++ b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md @@ -25,7 +25,7 @@ begin end; ``` -## Values +## Attribute values `CommitBehavior::Ignore` This will ignore all `commit` calls until the method scope ends. @@ -33,13 +33,14 @@ This will ignore all `commit` calls until the method scope ends. `CommitBehavior::Error` This will throw an exception and stop the execution of further code when a `commit` is called before the end of the scope of the method. -Note: We can only assign a more restrictive Commit Behavior. That is, if CommitBehavior::Ignore is attempted on a method scope, but the method calling the current method (let’s call it the parent method) is actually running with CommitBehavior::Error, then the current method will continue running with CommitBehavior::Error, even though Ignore attribute was specified. -The CommitBehavior only lasts for the method scope. -Regardless of whether the method finishes successfully or if an error causes the method to exit prematurely, the CommitBehavior reverts to the standard behavior, where COMMIT statements will commit to the database. +> [!NOTE] +> It is only possible to assign a more restrictive `commit` behavior. That is, if `CommitBehavior::Ignore` is attempted on a method scope, but the method calling the current method, e.g. the parent method is actually running with `CommitBehavior::Error`, then the current method will continue running with `CommitBehavior::Error`, even though the `Ignore` attribute was specified. - +> [!NOTE] +> The `CommitBehavior` only lasts for the method scope. Regardless of whether the method finishes successfully or if an error causes the method to exit prematurely, the `CommitBehavior` reverts to the standard behavior, where `commit` statements will commit to the database. + ## Example ``` From 163811a65ebbe6b2beb344a602e578dd25dfda81 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 16 Jul 2020 13:48:06 +0200 Subject: [PATCH 088/950] Update devenv-commitbehavior-attribute.md --- .../developer/methods/devenv-commitbehavior-attribute.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md index d745cdeb17..3d5d93eb44 100644 --- a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md +++ b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md @@ -38,7 +38,7 @@ This will throw an exception and stop the execution of further code when a `comm > It is only possible to assign a more restrictive `commit` behavior. That is, if `CommitBehavior::Ignore` is attempted on a method scope, but the method calling the current method, e.g. the parent method is actually running with `CommitBehavior::Error`, then the current method will continue running with `CommitBehavior::Error`, even though the `Ignore` attribute was specified. -> [!NOTE] +> [!NOTE] > The `CommitBehavior` only lasts for the method scope. Regardless of whether the method finishes successfully or if an error causes the method to exit prematurely, the `CommitBehavior` reverts to the standard behavior, where `commit` statements will commit to the database. ## Example @@ -55,21 +55,21 @@ codeunit 50100 MyCodeunit local procedure FunctionAllowCommit() begin FunctionIgnoreCommit(); - COMMIT; // This is valid, and Commit call will be executed. + commit; // This is valid, and commit call will be executed. end; [CommitBehavior(CommitBehavior::Ignore)] local procedure FunctionIgnoreCommit() begin TryFunctionErrorCommit(); - COMMIT; // This call will be silently ignored. + commit; // This call will be silently ignored. end; [CommitBehavior(CommitBehavior::Error)] [TryFunction] local procedure TryFunctionErrorCommit() begin - COMMIT; // This will throw an error. No further code will be executed and User will see a dialog to contact the System administrator. + commit; // This will throw an error. No further code will be executed and the user will see a dialog to contact the system administrator. end; var From 1d9fe3d681a261b531cc0e88248f62763f7dd282 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 16 Jul 2020 14:45:36 +0200 Subject: [PATCH 089/950] Update devenv-commitbehavior-attribute.md --- .../developer/methods/devenv-commitbehavior-attribute.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md index 3d5d93eb44..06f43d8238 100644 --- a/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md +++ b/dev-itpro/developer/methods/devenv-commitbehavior-attribute.md @@ -13,7 +13,7 @@ author: SusanneWindfeldPedersen # CommitBehavior Attribute -Specifies the behavior of `commit` calls inside the method scope of the call. +Specifies the behavior of `commit` calls inside the method scope of the call. This attribute can be used on both local and global methods. ## Syntax @@ -33,15 +33,14 @@ This will ignore all `commit` calls until the method scope ends. `CommitBehavior::Error` This will throw an exception and stop the execution of further code when a `commit` is called before the end of the scope of the method. - > [!NOTE] > It is only possible to assign a more restrictive `commit` behavior. That is, if `CommitBehavior::Ignore` is attempted on a method scope, but the method calling the current method, e.g. the parent method is actually running with `CommitBehavior::Error`, then the current method will continue running with `CommitBehavior::Error`, even though the `Ignore` attribute was specified. - > [!NOTE] > The `CommitBehavior` only lasts for the method scope. Regardless of whether the method finishes successfully or if an error causes the method to exit prematurely, the `CommitBehavior` reverts to the standard behavior, where `commit` statements will commit to the database. ## Example +The example shown below illustrates how the attribute is used on a local method; it can also be applied on a global method. ``` codeunit 50100 MyCodeunit From be771482ecbe664c6c056e72fc33817b0e1f9b4a Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Fri, 17 Jul 2020 11:08:40 +0200 Subject: [PATCH 090/950] Update devenv-export-permission-sets.md --- dev-itpro/developer/devenv-export-permission-sets.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dev-itpro/developer/devenv-export-permission-sets.md b/dev-itpro/developer/devenv-export-permission-sets.md index 79d03e8389..1f582c7ada 100644 --- a/dev-itpro/developer/devenv-export-permission-sets.md +++ b/dev-itpro/developer/devenv-export-permission-sets.md @@ -3,7 +3,7 @@ title: "Exporting Permission Sets" description: Export permission sets for Dynamics 365 for Business Central. author: SusanneWindfeldPedersen ms.custom: na -ms.date: 07/02/2020 +ms.date: 07/17/2020 ms.reviewer: na ms.suite: na ms.tgt_pltfrm: na @@ -40,6 +40,10 @@ Now, you have the XML file with default permissions to all your objects. The following example illustrates the generated .xml file from **MyProject** which contains a table with objectID 50106 and two object types are generated; `0` is `TableData` and `1` is `Table`. +> [!NOTE] +> The maximum length of the RoleID attribute is 20 characters. If the RoleID exceeds this length, then XML schema validation fails and the corresponding PermissionSet file is not included in the resulting app package. You will get a warning in the Visual Studio output panel. + + ```xml From 89ebc43485eff7c61166bc4a8d0c9d0f63e77b18 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Fri, 17 Jul 2020 11:10:54 +0200 Subject: [PATCH 091/950] Update devenv-export-permission-sets.md --- dev-itpro/developer/devenv-export-permission-sets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/developer/devenv-export-permission-sets.md b/dev-itpro/developer/devenv-export-permission-sets.md index 1f582c7ada..5b9bcba4ec 100644 --- a/dev-itpro/developer/devenv-export-permission-sets.md +++ b/dev-itpro/developer/devenv-export-permission-sets.md @@ -41,7 +41,7 @@ Now, you have the XML file with default permissions to all your objects. The following example illustrates the generated .xml file from **MyProject** which contains a table with objectID 50106 and two object types are generated; `0` is `TableData` and `1` is `Table`. > [!NOTE] -> The maximum length of the RoleID attribute is 20 characters. If the RoleID exceeds this length, then XML schema validation fails and the corresponding PermissionSet file is not included in the resulting app package. You will get a warning in the Visual Studio output panel. +> The maximum length of the RoleID attribute is 20 characters. If the RoleID exceeds this length, then the XML schema validation fails and the corresponding permission set file is not included in the resulting app package. You will get a warning in the Visual Studio output panel. ```xml From e9c893d7a9f953c904babeb2f1c7cdb130a81615 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Fri, 17 Jul 2020 11:12:12 +0200 Subject: [PATCH 092/950] Update devenv-export-permission-sets.md --- dev-itpro/developer/devenv-export-permission-sets.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev-itpro/developer/devenv-export-permission-sets.md b/dev-itpro/developer/devenv-export-permission-sets.md index 5b9bcba4ec..5daea08f34 100644 --- a/dev-itpro/developer/devenv-export-permission-sets.md +++ b/dev-itpro/developer/devenv-export-permission-sets.md @@ -75,7 +75,7 @@ The following example illustrates the generated .xml file from **MyProject** whi ### Object type mapping -The mapping of object types in the XML generated from Visual Studio Code is the following: +The mapping of object types in the XML such as `0` generated from Visual Studio Code is the following: |Object type |Number| |-----------------|------| @@ -96,6 +96,7 @@ The mapping of object types in the XML generated from Visual Studio Code is the ## See Also + [Permissions on Database Objects](devenv-permissions-on-database-objects.md) [Permissions Property](properties/devenv-permissions-property.md) [TestPermissions Property](properties/devenv-testpermissions-property.md) From d9ea340decaded4e54821d81c900fa49d60ac9f2 Mon Sep 17 00:00:00 2001 From: Eva Dupont Date: Fri, 24 Jul 2020 09:58:47 +0200 Subject: [PATCH 093/950] custom help toolkit round 1 --- dev-itpro/TOC.md | 2 + ...stom-help-toolkit-HtmlFromRepoGenerator.md | 107 ++++++++++++++++++ dev-itpro/help/custom-help-toolkit.md | 47 ++++++++ 3 files changed, 156 insertions(+) create mode 100644 dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md create mode 100644 dev-itpro/help/custom-help-toolkit.md diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index c004da618b..0514711e6a 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -11,6 +11,8 @@ #### [Configure Context-Sensitive Help](help/context-sensitive-help.md) #### [Configure the Help Experience](deployment/configure-help.md) #### [Migrate Legacy Help to the Business Central Format](upgrade/migrate-help.md) +#### [Custom Help Toolkit](help/custom-help-toolkit.md) +#### [Custom Help Toolkit: The HtmlFromRepoGenerator tool](help/custom-help-toolkit-HtmlFromRepoGenerator.md) ## Training and Readiness ### Learning Catalogs diff --git a/dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md b/dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md new file mode 100644 index 0000000000..35e897deb6 --- /dev/null +++ b/dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md @@ -0,0 +1,107 @@ +--- +title: Generate HTML files from the contents of a Microsoft GitHub repository +description: This article describes the HtmlFromRepoGenerator tool in the custom help toolkit for Business Central. + +author: edupont04 +ms.topic: article +ms.service: "dynamics365-business-central" +ms.date: 07/24/2020 +ms.author: edupont +--- + +# Custom Help Toolkit: The HtmlFromRepoGenerator tool + +The custom help toolkit includes the **HtmlFromRepoGenerator** tool that gets Microsoft's content in MarkDown files and converts it to HTML files. You can then deploy the HTML files to a website. + +## Use the HtmlFromRepoGenerator tool to get MarkDown files and generate HTML files + +HtmlFromRepoGenerator.exe provides functionality that supports the creation of custom Help based on source files from Microsoft. You can use HtmlFromRepoGenerator.exe to: + +- Clone a Microsoft documentation repo +- Remove developer and administrator content from your clone of the Microsoft repo +- Update links to files that are no longer in the clone +- Update the **ms.locale** value to match the language options that are supported by the Finance and Operations client + + The client uses language descriptors that are different from the language descriptors used in the corresponding GitHub repos. For localized custom Help to be called, the language indicators in the source content must be changed so that they match the client's languages. +- Generate HTML files that can be used for publishing. + + The HTML files will be generated in the **business-central** subfolder. The files are generated based on stylesheets and templates that are part of the tool. + +- Compare a localized Microsoft repo to the en-US repo to identify discrepancies and update links accordingly. + +### Syntax + +Here is the syntax for HtmlFromRepoGenerator.exe: + +``` +HtmlFromRepoGenerator.exe --Json --Out --ExternalText [--DoNotClone ] [--Repo ] [--RemoveGitFolder ] [--ReplaceUrl ] [--LogsDir <.\logs>] [--EnRepo ] [--EnOut ] [--Lng ] [--Rtl] [--?[--]] +``` + +The following table provides an explanation of the parameters: + +|Parameter |Description | +|------------|-------------| +|Json |Specifies a relative path for the location of the docfx.json file. In Microsoft documentation repos, this location is typically ```articles/```. | +|Out |Specifies the folder where your existing clone is, or the folder to clone the repo to. If you run HtmlFromRepoGenerator to clone a repo, this folder must not already exist. Use the language name as the folder name as described in [Language and locale descriptors in across product and Help](language-locale.md). | +|ExternalText |Specifies text that must be added to the updated links if HtmlFromRepoGenerator must replace the original links.| +|DoNotClone |Set this parameter when you run the tool against previously cloned repos. | +|Repo |Specifies the repo URL. Optional if you run the tool based on a previously cloned repo. Examples of Microsoft documentation repo URLs include *https://github.com/MicrosoftDocs/dynamics365smb-docs* for English (US) and *https://github.com/MicrosoftDocs/dynamics365smb-docs-pr.de-de* for German (Germany).| +|RemoveGitFolder|Specifies whether to remove the `.git` folder.| +|ReplaceUrl|Specifies the URL must replace links between files when the target files are not present. This parameter is intended to be used to turn relative links into absolute links.| +|LogsDir|Specifies the folder to save logs files to.| + +The following additional parameters are used when the tool is run against the localized Microsoft documentation repos: + +|Parameter |Description | +|------------|-------------| +|EnRepo|Specifies the URL of the en-US repo. Optional if you run the tool based on a previously cloned repo. The Microsoft documentation repo URL for English (US) is [https://github.com/MicrosoftDocs/dynamics365smb-docs](https://github.com/MicrosoftDocs/dynamics365smb-docs).| +|EnOut|Specifies the folder where the en-US repo exists, or the folder that it must be cloned to. This folder must not already exist if you run the tool based on a previously cloned repo.| +|Lng|Specifies the language value to use for `ms.locale` metadata in the generated HTML files. The value must correspond to the value that is specified in the [!INCLUDE [prodshort](../developer/includes/prodshort.md)] language settings. If this parameter is not set, the tool uses en-US. | +|Rtl|Set this parameter if the language uses right-to-left (RTL) formatting. Examples of RTL languages include Arabic and Hebrew.| + +## Examples + +> [!NOTE] +> The Microsoft repos contain many files, so the process takes several minutes. If you run the tool against multiple localization repos, the process takes longer. + +The following example clones the en-US repo and generates HTML files for en-US. + +``` +HtmlFromRepoGenerator.exe --json articles/ --out "D:\BC\en-US" --repo "https://github.com/MicrosoftDocs/dynamics365smb-docs" --externalText "(This is an external link)" --replaceUrl "https://docs.microsoft.com/en-us/dynamics365/business-central" --LogsDir D:\BC\logs\en-US +``` + +The following example uses a previously cloned en-US repo and generates HTML files for en-US. + +``` +HtmlFromRepoGenerator.exe --json articles/ --out "D:\BC\en-US" --externalText "(This is an external link)" --replaceUrl "https://docs.microsoft.com/en-us/dynamics365/business-central" --LogsDir D:\BC\logs\en-US +``` + +The following example clones both the de-DE and en-US repos, and generates HTML files for de. + +``` +HtmlFromRepoGenerator.exe --json articles/ --out "D:\BC\de" --repo "https://github.com/MicrosoftDocs/dynamics365smb-docs-pr.de-de" --externalText "(This is an external link)" --EnRepo "https://github.com/MicrosoftDocs/dynamics365smb-docs" --EnOut "D:\BC\en-us" --replaceUrl "https://docs.microsoft.com/de-de/dynamics365/business-central" --lng "de" --LogsDir D:\BC\logs\de +``` + +The following example uses the existing de-DE and en-US repos, and then generates HTML files for de. Make sure that the de-DE repo is up to date if you use the existing repo. + +``` +HtmlFromRepoGenerator.exe --json articles/ --out "D:\BC\de" --DoNotClone --externalText "(This is an external link)" --enOut "D:\BC\en-us" --replaceUrl "https://docs.microsoft.com/de-de/dynamics365/business-central" --lng "de" --LogsDir D:\BC\logs\de +``` + +> [!IMPORTANT] +> Do not run HtmlFromRepoGenerator.exe repeatedly on a previously-cloned repo. HtmlFromRepoGenerator modifies the links during processing, so running HtmlFromRepoGenerator more than once on the same content will result in incorrect links. If you want to rerun HtmlFromRepoGenerator, either use HtmlFromRepoGenerator to create a new clone of the repo, or revert all local changes to your existing clone. + +## Modifying the styling of the generated HTML files + +The tool generates the HTML files based a set of predefined templates. In most cases, you can modify the stylesheets in the ```d365F-O\styles``` folder to modify the appearance of your content. + +For advanced scenarios, you can modify the templates used by the HtmlFromRepoGenerator tool. The source files are included in the *SourceCode* folder in the GitHub repo. The templates are in the *SourceCode\HtmlFromRepoGenerator\HtmlFromRepoGenerator\HtmlFromRepoGenerator\Resources* subfolder. + +> [!NOTE] +> If you modify the templates, you must rebuild HtmlFromRepoGenerator.exe. + +For more information, see [Introduction to DocFX Template System](https://dotnet.github.io/docfx/tutorial/intro_template.html). + +## See also + +[Custom Help Toolkit](custom-help-toolkit.md) diff --git a/dev-itpro/help/custom-help-toolkit.md b/dev-itpro/help/custom-help-toolkit.md new file mode 100644 index 0000000000..02cd6e47ad --- /dev/null +++ b/dev-itpro/help/custom-help-toolkit.md @@ -0,0 +1,47 @@ +--- +title: Custom Help Toolkit +description: This article describes the components in the custom help toolkit for Business Central. +author: edupont04 + +ms.topic: article +ms.service: "dynamics365-business-central" +ms.date: 07/24/2020 +ms.author: edupont +--- + +# Custom Help Toolkit + +Microsoft has published a GitHub repository with scripts and tools that can help you prepare context-sensitive Help for your [!INCLUDE [prodshort](../developer/includes/prodshort.md)] solution. This context-sensitive Help can be accessed from the user interface through the *Learn more* links. + +## Tools in the toolkit + +The toolkit is available at TBD. The repo contains the following tools and the source code for the tools: + +- HtmlFromRepoGenerator tool + + For more information, see [Custom Help Toolkit: The HtmlFromRepoGenerator tool](custom-help-toolkit-HtmlFromRepoGenerator.md) + + + +## See also + +[Configure Context-Sensitive Help](context-sensitive-help.md) +[[!INCLUDE[prodlong](developer/includes/prodlong.md)] User Assistance Model](../user-assistance.md) From 31c397be433d4324fec99ee8f4022e4bd5456350 Mon Sep 17 00:00:00 2001 From: Eva Dupont Date: Fri, 24 Jul 2020 10:01:19 +0200 Subject: [PATCH 094/950] links --- dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md | 2 +- dev-itpro/help/custom-help-toolkit.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md b/dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md index 35e897deb6..08cd7e19e9 100644 --- a/dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md +++ b/dev-itpro/help/custom-help-toolkit-HtmlFromRepoGenerator.md @@ -42,7 +42,7 @@ The following table provides an explanation of the parameters: |Parameter |Description | |------------|-------------| |Json |Specifies a relative path for the location of the docfx.json file. In Microsoft documentation repos, this location is typically ```articles/```. | -|Out |Specifies the folder where your existing clone is, or the folder to clone the repo to. If you run HtmlFromRepoGenerator to clone a repo, this folder must not already exist. Use the language name as the folder name as described in [Language and locale descriptors in across product and Help](language-locale.md). | +|Out |Specifies the folder where your existing clone is, or the folder to clone the repo to. If you run HtmlFromRepoGenerator to clone a repo, this folder must not already exist. | |ExternalText |Specifies text that must be added to the updated links if HtmlFromRepoGenerator must replace the original links.| |DoNotClone |Set this parameter when you run the tool against previously cloned repos. | |Repo |Specifies the repo URL. Optional if you run the tool based on a previously cloned repo. Examples of Microsoft documentation repo URLs include *https://github.com/MicrosoftDocs/dynamics365smb-docs* for English (US) and *https://github.com/MicrosoftDocs/dynamics365smb-docs-pr.de-de* for German (Germany).| diff --git a/dev-itpro/help/custom-help-toolkit.md b/dev-itpro/help/custom-help-toolkit.md index 02cd6e47ad..bd37ea2d5b 100644 --- a/dev-itpro/help/custom-help-toolkit.md +++ b/dev-itpro/help/custom-help-toolkit.md @@ -44,4 +44,4 @@ The toolkit is available at TBD. The repo contains the following tools and the s ## See also [Configure Context-Sensitive Help](context-sensitive-help.md) -[[!INCLUDE[prodlong](developer/includes/prodlong.md)] User Assistance Model](../user-assistance.md) +[User Assistance Model](../user-assistance.md) From 186e1b46e2eae32147e1571fdfa339e83d33cc0c Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 29 Jul 2020 18:17:49 +0200 Subject: [PATCH 095/950] Update tenant-admin-center-environments.md --- .../tenant-admin-center-environments.md | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/dev-itpro/administration/tenant-admin-center-environments.md b/dev-itpro/administration/tenant-admin-center-environments.md index d77a569ae6..8e62fc1ca4 100644 --- a/dev-itpro/administration/tenant-admin-center-environments.md +++ b/dev-itpro/administration/tenant-admin-center-environments.md @@ -107,22 +107,28 @@ To cancel a session, select it from the list and then select **Cancel selected s > [!NOTE] > This feature is in preview. It might change or be removed in the future updates. -You can rename an environment by opening the environment card and clicking on the Rename button. +You can change the name of any environment. Before you change a name, consider that apart from uniquely identify the environment from your other environments, the name also is part of the environment's URL. The URL is used to access the environment in various ways - by application code and users. So changing the name can have significant impact. -In the Rename environment dialogue enter a new name to be used by this environment and click on Rename button. +### Before you rename an environment -Confirm your intent to rename the environment. - -> [!IMPORTANT] -> It is important you study ## Environment rename considerations to understand the consequences before you confirm your intent to rename. Additionally, this operation requires a restart to the environment. We recommend doing this when no users are active in Business Central. +- Carefully read the [Environment rename considerations](#consider) section to understand the consequences of renaming an environment. +- Determine the best time to do the remaining. + Renaming an environment requires a restart to the environment. We recommend doing this when no users are active in Business Central. + +### Rename an environment + +1. Open the environment you want to rename. +2. Select **Rename**. +3. On **Rename environment** page, enter the new name and then select **Rename**. +4. Confirm your intent to rename the environment. -The environment state will change to Preparing and back to Active again, once the rename has been completed. The new name will be available immediately. The environment will no longer be accessible using the old environment name. + At this point, the environment state will first change to **Preparing**, then to **Active** again when the rename has been completed. The new name will be available immediately. The environment will no longer be accessible using the old environment name. -You can also review the log of Rename operation on the Operations page afterwards. +You can also review the log for the Rename operation on the **Operations** page afterwards. -## Environment rename considerations +### Environment rename considerations -Environment name is a part of the environment URL, which uniquely identifies this environment among your other environments. Changing the name can affect many scenarios and integrations. While renaming an environment during early stages of a customer implementation may be a low risk operation, renaming an environment which has been used by customers for a longer period of time and is integrated with many external services and components is very risky and you must carefully plan for it. +Changing the name can affect many scenarios and integrations. Renaming an environment during early stages of a customer implementation may be a low risk operation. But renaming an environment that's been used by customers for a longer period of time or integrated with many external services and components is very risky. You must carefully plan for it. Here are some of the areas, which use the environment name, which you need to consider before attempting to rename an environment: From b9155cd418c25bfd03f783095a927a00ba3bb872 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 29 Jul 2020 18:53:41 +0200 Subject: [PATCH 096/950] Update tenant-admin-center-environments.md --- .../tenant-admin-center-environments.md | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/dev-itpro/administration/tenant-admin-center-environments.md b/dev-itpro/administration/tenant-admin-center-environments.md index 8e62fc1ca4..05211a3edb 100644 --- a/dev-itpro/administration/tenant-admin-center-environments.md +++ b/dev-itpro/administration/tenant-admin-center-environments.md @@ -111,7 +111,7 @@ You can change the name of any environment. Before you change a name, consider t ### Before you rename an environment -- Carefully read the [Environment rename considerations](#consider) section to understand the consequences of renaming an environment. +- Read the [Environment rename considerations](#consider) section to understand the consequences of renaming an environment. - Determine the best time to do the remaining. Renaming an environment requires a restart to the environment. We recommend doing this when no users are active in Business Central. @@ -119,8 +119,9 @@ You can change the name of any environment. Before you change a name, consider t 1. Open the environment you want to rename. 2. Select **Rename**. -3. On **Rename environment** page, enter the new name and then select **Rename**. -4. Confirm your intent to rename the environment. +3. On **Rename environment** page, read the information presented. +4. Enter the new name and then select **Rename**. +5. Confirm your intent to rename the environment. At this point, the environment state will first change to **Preparing**, then to **Active** again when the rename has been completed. The new name will be available immediately. The environment will no longer be accessible using the old environment name. @@ -130,46 +131,43 @@ You can also review the log for the Rename operation on the **Operations** page Changing the name can affect many scenarios and integrations. Renaming an environment during early stages of a customer implementation may be a low risk operation. But renaming an environment that's been used by customers for a longer period of time or integrated with many external services and components is very risky. You must carefully plan for it. -Here are some of the areas, which use the environment name, which you need to consider before attempting to rename an environment: +Here are some areas where the environment name is used, which you need to consider before attempting to rename an environment: -- Web Services URL +- Web services URL +- External integrations that use OData or SOAP +- Third-party apps (AppSource and per-tenant extensions) +- Web client URL +- Bookmarked links to web client +- Links created by users -- External integrations which use Odata or SOAP - -- 3rd Party apps (AppSource / Per tenant extensions ) - -- Web Client URL - -- Bookmarked links to Web client - -- User-created links - - - Links to records/filters/pages/reports/tables/Profiles/Companies on each user's browser(s) and device(s). Thru regular usage, these links inevitably get saved across repositories such as Emails, Teams channels, Word docs, Excels, OneNote, Calendars, exchanged amongst users in same company, across companies, across environments, across tenants. Links can also be in desktop shortcuts eg. "launch POS". + These links are stored in users' browsers and on devices. They target things like: records, filters, pages, reports, profiles, companies, and so on. Over time, these links inevitably get saved in various repositories such as emails, Teams channels, Word and Excel documents. They're often exchanged among users in the same company, across companies, across environments, across tenants. Links can also be in desktop shortcuts. > [!NOTE] - > Admins do not have access to some/most of the above and therefore cannot update EnvName in behalf of the user. + > Admins don't have access to some or most of these type of links, so they can't update the URL on behalf of users. + +- Links in the notification mails sent from Business Central. Links sent before the name change will no longer work after the name change. - - Links in the notification mails sent from BC before name change won't find the correct environment after the change. +- Partners, Partner Support, Customer admins, Customer IT Support can also embed web client links in documentation, support web sites, videos, and other material. Only some of these links can be updated by an admin. -- Partners, Partner Support, Customer Admins, Customer IT Support can also embed web client links in documentation, support websites, instructional steps and videos, and other material. Only some of this can be updated by an admin. +- Browser cache. -- Browser cache. We store the Url including environment name in some of our cached data. This is cached browser-side, that is, in the user's browser(s) across device(s). Admins typically don't have access or control this. When a user loses their cache, they lose micro-personalizations to all their pages, preferences to + We store the URL, including environment name, in some of our cached data. This data is cached browser-side, that is, in the user's browser and across devices. Admins typically don't have access or control this data cache. When users lose their cache, they lose micro-personalizations to all their pages and preferences. -- Integrations which embed the Web client - e.g. SharePoint apps composed of BC pages +- Integrations that embed the web client, for example, SharePoint apps composed of Business Central pages -- Integrations which launch the Web client +- Integrations that launch the web client -- Partner-developed mobile apps, web applications, etc. These likely originate from partners outside the customer's organization where the admin cannot update Urls. +- Partner-developed mobile apps, web applications, and so on. These apps likely originate from partners outside the customer's organization where the admin cannot update URLS. - Mobile apps incl. Windows 10 store app for desktop/tablet Affected only when users modify protocol handler before rename - to force the app to connect to environment with name different than "production". So if the user keeps working with "production" on mobile (which is default now), and the admin is renaming "prod2" to "myprod" the mobile user is not affected. Otherwise the app would throw an error and the user would have to bail out using a newly created protocol handler link. -- Effect on the Business Central add-ins and integrations with other Microsoft services +- Business Central add-ins and integrations with other Microsoft services - Outlook Add-in - The AddIn manifest saved into Exchange Server per org or per user includes the environment name. + The Add-In manifest that is saved to Exchange Server per org or per user includes the environment name. - Excel Add-in From 879abb6b5ace95a256a2c8fb481fad98a55cfe2e Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 30 Jul 2020 09:35:04 +0200 Subject: [PATCH 097/950] Update tenant-admin-center-environments.md --- .../tenant-admin-center-environments.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/dev-itpro/administration/tenant-admin-center-environments.md b/dev-itpro/administration/tenant-admin-center-environments.md index 05211a3edb..2d45e8d570 100644 --- a/dev-itpro/administration/tenant-admin-center-environments.md +++ b/dev-itpro/administration/tenant-admin-center-environments.md @@ -107,7 +107,7 @@ To cancel a session, select it from the list and then select **Cancel selected s > [!NOTE] > This feature is in preview. It might change or be removed in the future updates. -You can change the name of any environment. Before you change a name, consider that apart from uniquely identify the environment from your other environments, the name also is part of the environment's URL. The URL is used to access the environment in various ways - by application code and users. So changing the name can have significant impact. +You can change the name of any environment. Before you change a name, consider that apart from uniquely identify the environment from your other environments, the name also is part of the environment's URL. The URL is used in links to the environment in various ways. So changing the name can have significant impact. ### Before you rename an environment @@ -117,10 +117,10 @@ You can change the name of any environment. Before you change a name, consider t ### Rename an environment -1. Open the environment you want to rename. +1. Select **Environments**, then select the environment you want to rename. 2. Select **Rename**. -3. On **Rename environment** page, read the information presented. -4. Enter the new name and then select **Rename**. +3. On **Rename environment** page, read the information. +4. Enter the new name, and then select **Rename**. 5. Confirm your intent to rename the environment. At this point, the environment state will first change to **Preparing**, then to **Active** again when the rename has been completed. The new name will be available immediately. The environment will no longer be accessible using the old environment name. @@ -143,7 +143,7 @@ Here are some areas where the environment name is used, which you need to consid These links are stored in users' browsers and on devices. They target things like: records, filters, pages, reports, profiles, companies, and so on. Over time, these links inevitably get saved in various repositories such as emails, Teams channels, Word and Excel documents. They're often exchanged among users in the same company, across companies, across environments, across tenants. Links can also be in desktop shortcuts. > [!NOTE] - > Admins don't have access to some or most of these type of links, so they can't update the URL on behalf of users. + > Admins don't have access to some or most of these type of links, so they can't update the URL on behalf of users. - Links in the notification mails sent from Business Central. Links sent before the name change will no longer work after the name change. @@ -153,47 +153,47 @@ Here are some areas where the environment name is used, which you need to consid We store the URL, including environment name, in some of our cached data. This data is cached browser-side, that is, in the user's browser and across devices. Admins typically don't have access or control this data cache. When users lose their cache, they lose micro-personalizations to all their pages and preferences. -- Integrations that embed the web client, for example, SharePoint apps composed of Business Central pages +- Integrations that embed the web client, for example, SharePoint apps composed of Business Central pages - Integrations that launch the web client -- Partner-developed mobile apps, web applications, and so on. These apps likely originate from partners outside the customer's organization where the admin cannot update URLS. +- Partner-developed mobile apps, web applications, and so on. These apps likely originate from partners outside the customer's organization where the admin can't update URLS. -- Mobile apps incl. Windows 10 store app for desktop/tablet +- Mobile apps, including Windows 10 store app for desktop/tablet - Affected only when users modify protocol handler before rename - to force the app to connect to environment with name different than "production". So if the user keeps working with "production" on mobile (which is default now), and the admin is renaming "prod2" to "myprod" the mobile user is not affected. Otherwise the app would throw an error and the user would have to bail out using a newly created protocol handler link. + Affects only users who have modified the protocol handler, for example, to force the app to connect to environment with name other than "production". So if the user keeps working with "production" on the mobile app (which is default now), and the admin renames the environment from "prod2" to "myprod", the mobile user is not affected. Otherwise, the app would throw an error, and the user would have to exit using a newly created protocol handler link. -- Business Central add-ins and integrations with other Microsoft services +- Business Central add-ins and integrations with other Microsoft services - Outlook Add-in - The Add-In manifest that is saved to Exchange Server per org or per user includes the environment name. + The Add-In manifest that is saved to Exchange Server, per-organization or per-user, includes the environment name. - Excel Add-in - Each user's Excel sheet stores the Environment name. these Excels could be stored on user's desktop PCs, mobile devices, file shares, SharePointa, archives, etc. some of which will be unreachable by an admin to update. + Each user's Excel worksheet stores the environment name. These Excel worksheets can be stored in various locations, like the user's desktop PCs, mobile devices, file shares, SharePoint, archives, and more. Some locations are not accessible to admins. - Power BI - All reports built (including the default ones we deploy from Role Center) or any Power BI apps installed before rename would be affected with no automatic way to repair. Partner/user would have to manually update the connections. + All reports (including the default reports deployed from the Role Center) built before the rename and Power BI apps installed before the rename would be affected. There is no automatic way to repair these items. The partner or user would have to manually update the connections. - Power Apps/Automate - All apps/flows built before rename would be affected with no automatic way to repair. Partner/user would have to manually update the connections. + All apps/flows built before rename would be affected with no automatic way to repair. The partner or user would have to manually update the connections. - CDS - CDS Virtual Entity setup will store Environment name + CDS Virtual Entity setup stores environment name. - Accountant Hub - Development scenarios - - Publish to SB from VS Code. Launch.json configurations contain the sandbox name if different from "default", so these will be impacted and require source code updates + - Publish to sandbox environment from Visual Studio Code. The launch.json file of extensions might contain the sandbox name, if different from "default". The files require source code updates, - - CI/CD pipelines for test and deploy, these could be impacted by environment renames + - CI/CD pipelines for test and deployment could be impacted by environment renames. -- Azure AppInsights logs and metrics +- Azure Application Insights logs and metrics ## See also From 06240ad164b12dd87205bb16e8260eb360931b70 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 30 Jul 2020 09:36:19 +0200 Subject: [PATCH 098/950] Update tenant-admin-center-environments.md --- dev-itpro/administration/tenant-admin-center-environments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/administration/tenant-admin-center-environments.md b/dev-itpro/administration/tenant-admin-center-environments.md index 2d45e8d570..80d44642ad 100644 --- a/dev-itpro/administration/tenant-admin-center-environments.md +++ b/dev-itpro/administration/tenant-admin-center-environments.md @@ -193,7 +193,7 @@ Here are some areas where the environment name is used, which you need to consid - CI/CD pipelines for test and deployment could be impacted by environment renames. -- Azure Application Insights logs and metrics +- Azure Application Insights logs and metrics ## See also From a96e27db737bd332202352a395d52d02562d1dcb Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 30 Jul 2020 10:04:01 +0200 Subject: [PATCH 099/950] Update tenant-admin-center-environments.md --- .../tenant-admin-center-environments.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dev-itpro/administration/tenant-admin-center-environments.md b/dev-itpro/administration/tenant-admin-center-environments.md index 80d44642ad..efcb305efa 100644 --- a/dev-itpro/administration/tenant-admin-center-environments.md +++ b/dev-itpro/administration/tenant-admin-center-environments.md @@ -21,7 +21,7 @@ The **Environments** tab of the [!INCLUDE[prodadmincenter](../developer/includes ## Viewing details for an environment -In the list of environments, you can open a page with more details for an environment by choosing the link in the **Name** column of the list for the environment. +In the environments list, you can view more details by choosing the link in the **Name** column. > [!div class="mx-imgBorder"] > ![View details about an environment](../developer/media/admin/business_central_admin_center_details-v2.png) @@ -42,7 +42,7 @@ You can create environments of different types. Which type of environment to cho ## Create a new production environment -The [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)] provides an easy method for creating environments for the tenant. For example, if you have been using a production environment for training purposes, and you have decided to start using [!INCLUDE [prodshort](../developer/includes/prodshort.md)] to run the business, you can delete the original production environment and then create a new production environment. +The [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)] provides an easy method for creating environments for the tenant. For example, if you have been using a production environment for training purposes, and you've decided to start using [!INCLUDE [prodshort](../developer/includes/prodshort.md)] to run the business, you can delete the original production environment and then create a new production environment. > [!NOTE] > Each [!INCLUDE[prodshort](../developer/includes/prodshort.md)] tenant is limited to three production environments. @@ -51,7 +51,7 @@ To create a production environment: 1. On the **Environments** tab of the [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)], choose the **New** action on the action ribbon. 2. In the **Create Environment** pane, in the **Environment Type** list, choose **Production**. -3. In the **Country** list, select the country for the environment. The specified country determines the localization for the environment, as well as the Azure region in which the environment is created and stored. +3. In the **Country** list, select the country for the environment. The specified country determines the localization for the environment and the Azure region in which the environment is created and stored. 4. Select **Create**. When the new production environment is created, it will be based on the latest production version of [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. @@ -74,21 +74,21 @@ To create a sandbox environment: 4. Specify if you want the sandbox environment to contain a copy of another environment. If you choose this option, you must specify which environment to copy. > [!NOTE] > When you create a sandbox environment as a copy of another environment, the new environment is created on the same application version as the environment that you are copying. The new environment will also contain all per-tenant extensions and AppSource extensions that are installed and published in the original environment that is being copied. -5. In the **Country** list, select the country for the environment. The specified country determines the localization for the environment, as well as the Azure region in which the environment is created and stored. +5. In the **Country** list, select the country for the environment. The specified country determines the localization for the environment and the Azure region in which the environment is created and stored. 6. Choose the relevant application version for the new sandbox environment from the **Version** list if more than one version is available. 7. Select **Create**. > [!NOTE] - > The sandbox environment will not be accessible until the **State** shows *Active*. + > The sandbox environment won't be accessible until the **State** shows *Active*. To delete a sandbox environment, choose the environment on the **Environments** tab of the [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)], and then choose **Delete** on the action ribbon. ### Selecting a version for a new sandbox environment -If you choose to create a sandbox that is not a copy of an existing environment, you must specify an application version for the new environment. The version list will show the latest *production* version, which is the version used for new production environments. +If you create a sandbox that isn't a copy of an existing environment, you must specify an application version for the new environment. The version list will show the latest *production* version, which is the version used for new production environments. -The version list may also have one or more *preview* versions. Preview versions are early release candidates of upcoming releases of [!INCLUDE[prodshort](../developer/includes/prodshort.md)] that are made available specifically for sandbox environments. This gives you access to review new functionality, validate extension compatibility, and other general testing of the upcoming release. +The version list may also have one or more *preview* versions. Preview versions are early release candidates of upcoming releases of [!INCLUDE[prodshort](../developer/includes/prodshort.md)] that are made available specifically for sandbox environments. This list gives you access to review new functionality, validate extension compatibility, and other general testing of the upcoming release. -When you create a sandbox environment on a preview version, the environment will automatically be updated to new preview versions when they become available. However, the environment will not be updated to the production version. Once a sandbox environment is on a preview version, it must stay on a preview version until it is deleted. The environment can also be deleted if an update between preview versions fails. We recommend that preview versions are used only for temporary testing of an upcoming release. +When you create a sandbox environment on a preview version, the environment will automatically be updated to new preview versions when they become available. However, the environment won't be updated to the production version. Once a sandbox environment is on a preview version, it must stay on a preview version until it's deleted. The environment can also be deleted if an update between preview versions fails. We recommend that preview versions are used only for temporary testing of an upcoming release. ## Managing Sessions @@ -107,13 +107,13 @@ To cancel a session, select it from the list and then select **Cancel selected s > [!NOTE] > This feature is in preview. It might change or be removed in the future updates. -You can change the name of any environment. Before you change a name, consider that apart from uniquely identify the environment from your other environments, the name also is part of the environment's URL. The URL is used in links to the environment in various ways. So changing the name can have significant impact. +You can change the name of any environment. The name uniquely identifies the environment from your other environments. Before you change a name, you must consider that the name also is part of the environment's URL. The URL is used in links to the environment in various ways. So changing the name can have significant impact. ### Before you rename an environment - Read the [Environment rename considerations](#consider) section to understand the consequences of renaming an environment. - Determine the best time to do the remaining. - Renaming an environment requires a restart to the environment. We recommend doing this when no users are active in Business Central. + Renaming an environment requires a restart to the environment. We recommend doing this operation when no users are active in Business Central. ### Rename an environment @@ -129,7 +129,7 @@ You can also review the log for the Rename operation on the **Operations** page ### Environment rename considerations -Changing the name can affect many scenarios and integrations. Renaming an environment during early stages of a customer implementation may be a low risk operation. But renaming an environment that's been used by customers for a longer period of time or integrated with many external services and components is very risky. You must carefully plan for it. +Changing the name can affect many scenarios and integrations. Renaming an environment during early stages of a customer implementation may be a low risk operation. But renaming an environment that's been used by customers for a longer period of time or integrated with many external services and components is risky. You must carefully plan for it. Here are some areas where the environment name is used, which you need to consider before attempting to rename an environment: @@ -140,7 +140,7 @@ Here are some areas where the environment name is used, which you need to consid - Bookmarked links to web client - Links created by users - These links are stored in users' browsers and on devices. They target things like: records, filters, pages, reports, profiles, companies, and so on. Over time, these links inevitably get saved in various repositories such as emails, Teams channels, Word and Excel documents. They're often exchanged among users in the same company, across companies, across environments, across tenants. Links can also be in desktop shortcuts. + These links are stored in users' browsers and on devices. They target things like: records, filters, pages, reports, profiles, companies, and so on. Over time, these links inevitably get saved in various repositories such as emails, Teams channels, Word, and Excel documents. They're often exchanged among users in the same company, across companies, across environments, across tenants. Links can also be in desktop shortcuts. > [!NOTE] > Admins don't have access to some or most of these type of links, so they can't update the URL on behalf of users. @@ -151,7 +151,7 @@ Here are some areas where the environment name is used, which you need to consid - Browser cache. - We store the URL, including environment name, in some of our cached data. This data is cached browser-side, that is, in the user's browser and across devices. Admins typically don't have access or control this data cache. When users lose their cache, they lose micro-personalizations to all their pages and preferences. + We store the URL, including environment name, in some of our cached data. This data is cached browser-side, that is, in the user's browser and across devices. Admins typically don't have access or control this data cache. When users lose their cache, they lose the link modifications to all their pages and preferences. - Integrations that embed the web client, for example, SharePoint apps composed of Business Central pages @@ -161,21 +161,21 @@ Here are some areas where the environment name is used, which you need to consid - Mobile apps, including Windows 10 store app for desktop/tablet - Affects only users who have modified the protocol handler, for example, to force the app to connect to environment with name other than "production". So if the user keeps working with "production" on the mobile app (which is default now), and the admin renames the environment from "prod2" to "myprod", the mobile user is not affected. Otherwise, the app would throw an error, and the user would have to exit using a newly created protocol handler link. + Affects only users who have modified the protocol handler to force the app to connect to environment with name other than "production". If the user keeps working with "production" on the mobile app (which is default now), and the admin renames the environment from "prod2" to "myprod", the mobile user isn't affected. Otherwise, the app would throw an error, and the user would have to exit using a newly created protocol handler link. - Business Central add-ins and integrations with other Microsoft services - Outlook Add-in - The Add-In manifest that is saved to Exchange Server, per-organization or per-user, includes the environment name. + The Add-In manifest that is saved to Exchange Server, either per-organization or per-user, includes the environment name. - Excel Add-in - Each user's Excel worksheet stores the environment name. These Excel worksheets can be stored in various locations, like the user's desktop PCs, mobile devices, file shares, SharePoint, archives, and more. Some locations are not accessible to admins. + Each user's Excel worksheet stores the environment name. These Excel worksheets can be stored in various locations, like: the user's desktop PCs, mobile devices, file shares, SharePoint, archives. Some locations aren't accessible to admins. - Power BI - All reports (including the default reports deployed from the Role Center) built before the rename and Power BI apps installed before the rename would be affected. There is no automatic way to repair these items. The partner or user would have to manually update the connections. + All reports, including the default reports deployed from the Role Center, built before the rename will be affected. Also, Power BI apps installed before the rename would be affected. There's no automatic way to repair these items. The partner or user would have to manually update the connections. - Power Apps/Automate From 0b4c4e82ec4edc7d62a3040828c1df9260437940 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 30 Jul 2020 14:59:33 +0200 Subject: [PATCH 100/950] tech rev --- .../telemetry-app-key-vault-trace.md | 0 dev-itpro/TOC.md | 2 +- .../setup-app-key-vault-onprem.md | 14 ++---------- .../administration/telemetry-event-ids.md | 8 +++---- .../administration/telemetry-overview.md | 2 +- dev-itpro/developer/devenv-app-key-vault.md | 22 +++++++++---------- dev-itpro/developer/devenv-json-files.md | 3 ++- 7 files changed, 21 insertions(+), 30 deletions(-) rename {dev-itpro/administration => Upgrade-archive}/telemetry-app-key-vault-trace.md (100%) diff --git a/dev-itpro/administration/telemetry-app-key-vault-trace.md b/Upgrade-archive/telemetry-app-key-vault-trace.md similarity index 100% rename from dev-itpro/administration/telemetry-app-key-vault-trace.md rename to Upgrade-archive/telemetry-app-key-vault-trace.md diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index f36f802b26..0a94242640 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -76,7 +76,7 @@ ### [Prepare for Major Updates with Preview Environments](administration/preview-environments.md) ## Monitoring and Analyzing Telemetry ### [Overview](administration/telemetry-overview.md) -### [App Key Vault Secret Telemetry](administration/telemetry-app-key-vault-trace.md) +### [App Key Vault Secret Telemetry](administration/telemetry-extension-key-vault-trace.md) ### [Authorization Telemetry](administration/telemetry-authorization-trace.md) ### [Company Lifecycle Telemetry](administration/telemetry-company-lifecycle-trace.md) ### [Database Lock Timeout Telemetry](administration/telemetry-database-locks-trace.md) diff --git a/dev-itpro/administration/setup-app-key-vault-onprem.md b/dev-itpro/administration/setup-app-key-vault-onprem.md index 48f28b12a4..4c229bbc76 100644 --- a/dev-itpro/administration/setup-app-key-vault-onprem.md +++ b/dev-itpro/administration/setup-app-key-vault-onprem.md @@ -40,17 +40,7 @@ To complete the tasks in this article, you need: ## Create the Azure Key Vault with secrets -Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. An extension can be set up with one or two key vaults. This step requires an Azure subscription. Because your solution is using Azure AD authentication, you should already have one. - - +Now, you create one or more key vaults in Azure, and add the secrets that you want to make available to your extensions. An extension can be set up with one or two key vaults. There are different ways to create an Azure key vault. For example, you can use the Azure portal, Azure CLI, and more. @@ -108,7 +98,7 @@ The steps in this task are done from the [Azure portal](https://portal.azure.com At this point, the work in Azure is finished. -## Configure the Business Central Server for the Apps Key Vault +## Configure the Business Central Server to use the Apps Key Vault feature Next, you configure the [!INCLUDE[server](../developer/includes/server.md)] instance to use the key vault reader application and its certificate, which you registered in Azure AD, for authenticating to the key vaults. diff --git a/dev-itpro/administration/telemetry-event-ids.md b/dev-itpro/administration/telemetry-event-ids.md index e143c4fd40..db3b841abc 100644 --- a/dev-itpro/administration/telemetry-event-ids.md +++ b/dev-itpro/administration/telemetry-event-ids.md @@ -31,10 +31,10 @@ The following tables list the IDs of [!INCLUDE[prodshort](../developer/includes/ |RT0010|Extension lifecycle|[Extension Update Failed: exception raised in extension {extensionName} by {extensionPublisher} (updating to version {extensionTargetedVersion})](telemetry-extension-update-trace.md#extension-update-failed-exception-raised-in-extension) | | RT0012 | Performance | [Database lock timed out](telemetry-database-locks-trace.md#database-lock-timed-out) | | RT0013 | Performance | [Database lock snapshot: {snapshotId}](telemetry-database-locks-trace.md#database-lock-snapshot) | -| RT0014 | Security | [App Key Vault initialization succeeded: '{keyVaultUri}'](telemetry-app-key-vault-trace.md#initializedsuccess) | -| RT0015 | Security | [App Key Vault initialization failed](telemetry-app-key-vault-trace.md#initializedfailed) | -| RT0016 | Security | [App Key Vault secret retrieval succeeded from key vault '{keyVaultUri}'](telemetry-app-key-vault-trace.md#retrievedsuccess) | -| RT0017 | Security | [App Key Vault secret retrieval failed from key vault: '{keyVaultUri}'](telemetry-app-key-vault-trace.md#retrievedfailed) | +| RT0014 | Security | [App Key Vault initialization succeeded: '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#initializedsuccess) | +| RT0015 | Security | [App Key Vault initialization failed](telemetry-extension-key-vault-trace.md#initializedfailed) | +| RT0016 | Security | [App Key Vault secret retrieval succeeded from key vault '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#retrievedsuccess) | +| RT0017 | Security | [App Key Vault secret retrieval failed from key vault: '{keyVaultUri}'](telemetry-extension-key-vault-trace.md#retrievedfailed) | ## Lifecycle events diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 2a7636a797..e6766b3b43 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -26,7 +26,7 @@ In Application Insights, telemetry from [!INCLUDE[prodshort](../developer/includ |Area | Description |Online/On-premises|See more| |----------|-------------|-----------------|--------| -|App Key Vault secrets |Provides information about the retrieval of secrets from Azure Key Vaults by extensions.|Both|[Analyzing App Key Vault Secret Trace Telemetry](telemetry-app-key-vault-trace.md) | +|App Key Vault secrets |Provides information about the retrieval of secrets from Azure Key Vaults by extensions.|Both|[Analyzing App Key Vault Secret Trace Telemetry](telemetry-extension-key-vault-trace.md) | |Authorization|Provides information about user sign-in attempts. Information includes success or failure indication, reason for failure, user type, and more.|Online|[Analyzing Authentication Telemetry](telemetry-authorization-trace.md) | |Company lifecycle|Provides information about creating, copying, and deleting of companies.|Both|[Analyzing Company Lifecycle Telemetry](telemetry-company-lifecycle-trace.md) | |Database lock timeouts|Provides information about database locks that have timed out. |Both|[Database Lock Timeout Telemetry](telemetry-database-locks-trace.md)| diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md index bd2d6a20ec..b72be93e7b 100644 --- a/dev-itpro/developer/devenv-app-key-vault.md +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -12,7 +12,7 @@ author: jswymer --- # Using Key Vault Secrets in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions -This article describes how to code an extension to retrieve secrets from Azure Key Vaults. Secrets are a kind of credential used for authenticating en extension. Secrets are typically used when the extensions calls a web service. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](../devenv-app-key-vault-overview.md). +This article describes how to code an extension to retrieve secrets from Azure Key Vaults. Secrets are typically used when the extensions calls a web service. For an overview of app key vaults and secrets, see [Using App Key Vaults with Extensions](devenv-app-key-vault-overview.md). Developing an extension to use secrets from a key vault involves two tasks, as described in this article: @@ -44,10 +44,10 @@ You can specify up to two key vaults in the app.json, as shown in the following     ] ``` -Specifying two key vaults ensures a higher availability of secrets. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate both key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute because the other key vault will most likely be available. +Specifying two key vaults ensures a higher availability of secrets, especially if created in two different Azure regions. At runtime, the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] platform will iterate both key vaults until the secret is successfully retrieved. If one of the key vaults is unavailable for any reason, the extension will continue to execute because the other key vault will most likely be available. -## Add code to retrieve secrets the key vault +## Add code to retrieve secrets from the key vault Next, you add code to the extension for reading secrets from the key vault at runtime. To read secrets, you use the **Secrets** module of the System Application. Specifically, you'll use codeunit **3800 "App Key Vault Secret Provider"**. This codeunit includes two methods: @@ -56,7 +56,7 @@ Next, you add code to the extension for reading secrets from the key vault at ru | `TryInitializeFromCurrentApp(): Boolean`|Identifies the calling extension and initializes the codeunit with the key vaults specified in the extension's manifest.| | `GetSecret(SecretName: Text, var SecretValue: Text): Boolean`|Retrieves the value of a specific secret from one of the app's key vaults.| -Look at following example for a simple page object. The code retrieves the value of the secret named **MySecret** in app key vault: +Look at the following example for a simple page object. The code retrieves the value of the secret named **MySecret** in app key vault: ``` page 50100 HelloWorldPage @@ -96,18 +96,18 @@ Once the **App Key Vault Secret Provider** codeunit has been initialized, it can - If you pass the codeunit to another method, then that method is also able use it. - If you pass the codeunit to a method in another extension, then the other extension can also use the secret provider to get secrets. -These conditions may not be what you want, so be careful with who you pass the secret provider. +These conditions may not be what you want, so be careful who you pass the secret provider to. -### Run publisher validation +### Enable publisher validation -For on-premises deployments, you can configure [!INCLUDE[server](../developer/includes/server.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the server's **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabledPublisher) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. +For on-premises deployments, you can configure [!INCLUDE[server](../developer/includes/server.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the server's **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabled) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. > [!TIP] > With a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online production environment, publisher validation is not performed for per-tenant extensions. Publisher validation is done automatically for onboarded AppSource extensions. #### How it works -Publisher validation is done by comparing the key vault secret provider's Azure AD tenant ID with the extension publisher's Azure AD tenant ID. It works this way: +Publisher validation is done by comparing the key vault's Azure AD tenant ID with the extension publisher's Azure AD tenant ID. It works this way: 1. When an extension is published by using the [Publish-NAVApp cmdlet](/powershell/module/microsoft.dynamics.nav.apps.management/publish-navapp), the publisher can provide their Azure AD tenant ID by setting the `-PublisherAzureActiveDirectoryTenantId` parameter: @@ -119,7 +119,7 @@ Publisher validation is done by comparing the key vault secret provider's Azure > An error won't occur if `-PublisherAzureActiveDirectoryTenantId` isn't set. There is nothing preventing you from publishing the extension at this point. 2. When the extension runs, it tries to initialize the **App Key Vault Secret Provider** codeunit. -3. The system compares the key vault secret provider's Azure AD tenant ID with the Azure AD tenant ID published with the extension: +3. The system compares the key vault's Azure AD tenant ID with the Azure AD tenant ID published with the extension: - If they match, initialization succeeds. - If they don't match, an error occurs. @@ -164,11 +164,11 @@ You can set up extensions to emit telemetry to an Application Insights resource 2. In the app.json file of the extension, add the `"applicationInsightsKey"`: ``` - "applicationInsightsKey": [""] + "applicationInsightsKey": [""] ``` 3. Now, you can run your extensions and view data in Application Insights. - For more information, see [Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) and [Analyzing App Key Vault Secret Trace Telemetry](../administration/telemetry-app-key-vault-trace.md). + For more information, see [Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) and [Analyzing App Key Vault Secret Trace Telemetry](../administration/telemetry-extension-key-vault-trace.md). ## See Also [Getting Started with AL](devenv-get-started.md) diff --git a/dev-itpro/developer/devenv-json-files.md b/dev-itpro/developer/devenv-json-files.md index ec5cac65fe..4e9198cd48 100644 --- a/dev-itpro/developer/devenv-json-files.md +++ b/dev-itpro/developer/devenv-json-files.md @@ -51,7 +51,7 @@ The following table describes the settings in the `app.json` file: |features|No|Specifies a list of options for translations. The `TranslationFile` option generates a `\Translations` folder that is populated with the .xlf file that contains all the labels, label properties, and report labels that you are using in the extension. The `GenerateCaptions` option depends on the `TranslationFile` setting. It generates captions for objects that do not have a `Caption` or `CaptionML` specified, these are then written to the .xlf file.
The syntax is `"features": [ "TranslationFile", "GenerateCaptions" ]`. For more information, see [Working with Translation Files](devenv-work-with-translation-files.md)| |internalsVisibleTo|No|Specifies a list of modules that have access to the objects that are marked as `Internal` using the **Access** property from the current module.
The syntax is `{ "appId": "d6c3f231-08d3-4681-996f-261c06500e1a", "name": "TheConsumer", "publisher": "Microsoft"}]`. For more information see [Access Property](properties/devenv-access-property.md) and [InternalEvent Attribute](methods/devenv-internal-attribute.md).| |propagateDependencies|No|Specifies whether the dependencies of this project should be propagated as direct dependencies of projects that depend on this one. Default is `false`. If set to `true` then any dependencies of the current package will be visible to consumers of the package. For example, if A depends on B that depends on C, by default, A will not be able to use types defined in C. If B has `"propagateDependencies" : "true"`, then A will be able to use types defined in C without taking a direct dependency.
**Note:** `propagateDependencies` applies to all dependencies, there is no option to exclude specific dependencies.| -|applicationInsightsKey|The instrumentation key of the Azure Application Insights resource for monitoring app secrets retrieval by extensions.

For more information, see [App Key Vaults](../devenv-app-key-vault-overview.md)| +|applicationInsightsKey|The instrumentation key of the Azure Application Insights resource for monitoring operations, for example, like app secrets retrieval by extensions.

For more information, see [Monitoring and Analyzing Telemetry](../administrartion/telemetry-overview.md).| |keyVaultUrls|No|List of URLs of key vaults that the extension from which the extension can retrieve secrets. For example: `"keyVaultUrls": [ "https://myfirstkeyvault.vault.azure.net", "https://mysecondkeyvault.vault.azure.net" ]`.

For more information, see [App Key Vaults](../devenv-app-key-vault-overview.md). ## Launch.json file @@ -112,3 +112,4 @@ The following table describes the settings in the `launch.json` file. The `launc [Security Setting and IP Protection](devenv-security-settings-and-ip-protection.md) [AL Language Extension Configuration](devenv-al-extension-configuration.md) [Configure Context-Sensitive Help](../help/context-sensitive-help.md) +[App Key Vaults](devenv-app-key-vault-overview.md) From b1fb420b73f33e17dc85acad4c22d602ae053888 Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 30 Jul 2020 15:17:52 +0200 Subject: [PATCH 101/950] fix --- dev-itpro/developer/devenv-app-key-vault-overview.md | 2 +- dev-itpro/developer/devenv-app-key-vault.md | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/dev-itpro/developer/devenv-app-key-vault-overview.md b/dev-itpro/developer/devenv-app-key-vault-overview.md index 042eace59d..91fc667430 100644 --- a/dev-itpro/developer/devenv-app-key-vault-overview.md +++ b/dev-itpro/developer/devenv-app-key-vault-overview.md @@ -14,7 +14,7 @@ author: jswymer Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make web service calls to non-[!INCLUDE[prodshort](../developer/includes/prodshort.md)] services. For example, one extension might call Azure Storage to read/write blobs. Another extension might call the extension publisher's web service to do an operation. -These web service calls are typically authenticated, which means the extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? Here is where Azure Key Vaults is used. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, enabling you to control access and distribution of the secrets. +These web service calls are typically authenticated, which means the extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? Here is where Azure Key Vault is used. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, enabling you to control access and distribution of the secrets. ## Getting started diff --git a/dev-itpro/developer/devenv-app-key-vault.md b/dev-itpro/developer/devenv-app-key-vault.md index b72be93e7b..4b94b47f1c 100644 --- a/dev-itpro/developer/devenv-app-key-vault.md +++ b/dev-itpro/developer/devenv-app-key-vault.md @@ -102,9 +102,6 @@ These conditions may not be what you want, so be careful who you pass the secret For on-premises deployments, you can configure [!INCLUDE[server](../developer/includes/server.md)] to run with or without publisher validation of key vault secret providers. Publisher validation is controlled by the server's **Enable Publisher Validation** (AzureKeyVaultAppSecretsPublisherValidationEnabled) configuration setting. The validation is a runtime operation that ensures extensions use only key vaults that belong to their publishers. It essentially blocks attempts in AL to read secrets from another publisher's key vault. -> [!TIP] -> With a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online production environment, publisher validation is not performed for per-tenant extensions. Publisher validation is done automatically for onboarded AppSource extensions. - #### How it works Publisher validation is done by comparing the key vault's Azure AD tenant ID with the extension publisher's Azure AD tenant ID. It works this way: From ea0c95015cfbaa522bcd5bcd666d85c10f68471e Mon Sep 17 00:00:00 2001 From: Mike Borg Cardona Date: Thu, 30 Jul 2020 17:47:14 +0200 Subject: [PATCH 102/950] Update devenv-inspecting-pages.md Removed limitation about temporary tables. Pointed out differences for SmartLists that are based on Queries. Aligned wording for how we talk about parts. Updated terminology about tenants vs environments --- dev-itpro/developer/devenv-inspecting-pages.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dev-itpro/developer/devenv-inspecting-pages.md b/dev-itpro/developer/devenv-inspecting-pages.md index 11595f437f..406c18f003 100644 --- a/dev-itpro/developer/devenv-inspecting-pages.md +++ b/dev-itpro/developer/devenv-inspecting-pages.md @@ -1,9 +1,9 @@ --- title: Inspecting Pages -description: "Provides and overview of Role Center design" +description: "Learn about the structure of a page and its' underlying data." author: jswymer ms.custom: na -ms.date: 04/01/2020 +ms.date: 07/30/2020 ms.reviewer: na ms.suite: na ms.tgt_pltfrm: na @@ -37,7 +37,7 @@ As you navigate to other pages in the application, the **Page Inspection** pane ## What Page Inspection Shows -In short, the page inspection pane shows the information for the main page or sub-page in a part, the page's source table (if any) and fields, extensions that affect the page, and current filters applied to the page. The following sections describe details about what is shown. +In short, the page inspection pane shows the information for the main page or page part, the page's source table (if any) and fields, extensions that affect the page, and current filters applied to the page. The following sections describe details about what is shown. > [!NOTE] > If you do not see all details described below, you might not have the required permissions. For more information, see [Controlling Access to Page Inspection Details](/dynamics365/business-central/across-inspect-page?#controlling-access-to-page-inspection). @@ -69,11 +69,13 @@ The **Page** field shows information about the main page or a selected (highligh ### [Table](#tab/table) -If the page is associated with a source table, the **Table** field displays information about the source table of the main page or the selected page in a part, as specified by the page's [SourceTable property](properties/devenv-sourcetable-property.md). The **Table** field shows the following information: +If the page is associated with a source table, the **Table** field displays information about the source table of the main page or the selected page part, as specified by the page's [SourceTable property](properties/devenv-sourcetable-property.md). The **Table** field shows the following information: - The name, as specified by its [Name property](properties/devenv-name-property.md) - The ID as specified by the [ID property](properties/devenv-id-property.md). +If the page uses a query object as a data source, the table field shows the query name and ID instead. + #### View Table If a page has a source table, the **View table** link is available. This link will open the table in a separate browser window, allowing you to see all records and fields in the table. @@ -99,12 +101,11 @@ Each field is shown with the following information: #### What field information is not shown - Page fields that are not bound to the source table by the [SourceExp property](properties/devenv-sourceexpr-property.md). -- Fields in temporary tables. - The value of fields that have a data type of blob, byte, media, or mediaset. ## [Extensions](#tab/extensions) -The **Extensions** tab displays extensions that are installed on the tenant and affect the selected page or its source table. +The **Extensions** tab displays extensions that are installed for the current environment and affect the selected page or its source table. ![Page Inspection](media/page-inspection-extensions.png) @@ -138,4 +139,4 @@ The following table describes the different filter types. [Actions Overview](devenv-actions-overview.md) [Adding Pages and Reports to Search](devenv-al-menusuite-functionality.md) [Personalizing Your Workspace](/dynamics365/business-central/ui-personalization-user) -[Using Designer](devenv-inclient-designer.md) \ No newline at end of file +[Using Designer](devenv-inclient-designer.md) From f93d13f8df95094b84f9fffbc0bf887cdd09682c Mon Sep 17 00:00:00 2001 From: Mike Borg Cardona Date: Thu, 30 Jul 2020 17:52:06 +0200 Subject: [PATCH 103/950] Add files via upload updated to latest client visuals --- .../media/page-inspection-example.png | Bin 76921 -> 334386 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/dev-itpro/developer/media/page-inspection-example.png b/dev-itpro/developer/media/page-inspection-example.png index d155de34d5ffa6b9e0059421e34dfb775d6092ae..58639f7427921502309fabec118b11e76f730119 100644 GIT binary patch literal 334386 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μ{R+M4Sa3i@eqM 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 literal 76921 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 From 2512f702aa5bb33fc814ac66879d3b909fdb03e7 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 31 Jul 2020 13:05:43 +0200 Subject: [PATCH 104/950] Update devenv-app-key-vault-overview.md --- dev-itpro/developer/devenv-app-key-vault-overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-app-key-vault-overview.md b/dev-itpro/developer/devenv-app-key-vault-overview.md index 91fc667430..fc113e6d72 100644 --- a/dev-itpro/developer/devenv-app-key-vault-overview.md +++ b/dev-itpro/developer/devenv-app-key-vault-overview.md @@ -24,8 +24,8 @@ Getting extensions to use secrets from Azure Key Vault involves two areas of wor An extension can retrieve secrets from one or two different Azure Key Vaults. These key vaults must be created in Azure, and the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] service configured to access key vaults. The setup process is different for online and on-premises. For more information, see: -- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](setup-app-key-vault.md) -- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises](setup-app-key-vault-onprem.md) +- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online](../administration/setup-app-key-vault.md) +- [Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises](../administration/setup-app-key-vault-onprem.md) ### Developing the extensions to use secrets from Azure Key Vault From 7543cb29891a535f3c47f09dd32fb9dafe06d4b1 Mon Sep 17 00:00:00 2001 From: jswymer Date: Fri, 31 Jul 2020 15:24:18 +0200 Subject: [PATCH 105/950] fix --- dev-itpro/administration/setup-app-key-vault.md | 2 +- dev-itpro/developer/devenv-app-key-vault-overview.md | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dev-itpro/administration/setup-app-key-vault.md b/dev-itpro/administration/setup-app-key-vault.md index e0c1c538bb..2d34eab41c 100644 --- a/dev-itpro/administration/setup-app-key-vault.md +++ b/dev-itpro/administration/setup-app-key-vault.md @@ -12,7 +12,7 @@ author: jswymer --- # Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online -In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the Azure Key Vault feature is available for all App Source apps. However, there are some onboarding tasks required. +AppsSource apps for [prodshort](../developer/includes/prodshort.md)] can be developed to get secrets from Azure Keys Vaults. The app key feature is readily available for use on the service by all App Source apps. However, there are some onboarding tasks required. ## Create the Azure Key Vault with secrets diff --git a/dev-itpro/developer/devenv-app-key-vault-overview.md b/dev-itpro/developer/devenv-app-key-vault-overview.md index fc113e6d72..37c3b11f38 100644 --- a/dev-itpro/developer/devenv-app-key-vault-overview.md +++ b/dev-itpro/developer/devenv-app-key-vault-overview.md @@ -16,9 +16,12 @@ Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make w These web service calls are typically authenticated, which means the extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? Here is where Azure Key Vault is used. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, enabling you to control access and distribution of the secrets. +> [NOTE] +> For [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the app key vault feature is only supported for AppSource extensions. + ## Getting started -Getting extensions to use secrets from Azure Key Vault involves two areas of work: +Getting extensions to use secrets from Azure Key Vault involves two areas of work: setting up and configuring Azure Key Vaults and developing the extensions to use secrets from Azure Key Vault. ### Setting up and configuring Azure Key Vaults From fd0b3faf008ca3129ebb016ed35c54dd53ef4b8d Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 6 Aug 2020 08:56:22 +0200 Subject: [PATCH 106/950] Update configure-server-instance.md --- dev-itpro/administration/configure-server-instance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/administration/configure-server-instance.md b/dev-itpro/administration/configure-server-instance.md index d69de6183a..c674d40f4c 100644 --- a/dev-itpro/administration/configure-server-instance.md +++ b/dev-itpro/administration/configure-server-instance.md @@ -294,7 +294,7 @@ The following table describes fields on the **Reports** tab in the [!INCLUDE[adm | Enable Save as Word on Request Pages of RDLC-layout Reports | EnableSaveToWordForRdlcReports| Specifies whether users can open or save a report as a Microsoft Word document if the report uses an RDLC layout.

If you clear this check box, the **Word** option is removed from the **Print** menu on the request page.

Default: Enabled
Dynamically Updatable: No| | Enable Save from Report Preview | EnableSaveFromReportPreview| Specifies whether users can save a report as a PDF, Microsoft Word, or Microsoft Excel document from the report preview window.

If you clear this check box, the **Save As** icon is removed from the report preview window.

Default: Enabled
Dynamically Updatable: No| | Enforce Cloud Print Support | ReportCloudPrintingEnforced | Specifies whether cloud printing is supported for reports. This setting must be enabled to send print jobs to any printer that is set up by an extension that subscribes to the OnAfterDocumentPrintReady event.

If you disable this setting, the OnAfterDocumentPrintReady event is never raised, and print jobs are directed to the default printing on the server.

Default: Enabled
Dynamically Updatable: No| -| Max Dcouments | ReportMaxDocuments | Specifies the maximum number of documents that can be merged when using [WordMergeDataItem](../developer/properties/devenv-wordmergedataitem-property.md) property on reports using a Word layout. If exceeded, the report will be canceled by the server. To turn off this limit set the value to **MaxValue**.

Timeout format: [dd.]hh:mm:ss[.ff]

Default: MaxValue
Dynamically Updatable: Yes| +| Max Documents | ReportMaxDocuments | Specifies the maximum number of documents that can be merged when using [WordMergeDataItem](../developer/properties/devenv-wordmergedataitem-property.md) property on reports using a Word layout. If exceeded, the report will be canceled by the server. To turn off this limit set the value to **MaxValue**.

Timeout format: [dd.]hh:mm:ss[.ff]

Default: MaxValue
Dynamically Updatable: Yes| | Max Execution Timeout | ReportTimeout | Specifies the maximum execution time that it can take to generate a report. If exceeded, the report will be canceled by the server. If you don't want a limit, set the value to **MaxValue**.

For more information about how reports are canceled, see [Report Generation and Cancellation Flow](report-cancellation.md).

Timeout format: [dd.]hh:mm:ss[.ff]

Default: MaxValue
Dynamically Updatable: Yes| | Max Rows | ReportMaxRows | Specifies the maximum number of rows that can be processed in a report. If exceeded, the report will be canceled by the server. You can also use MaxValue to indicate no limit. If you don't want a limit, set the value to **MaxValue**.

For more information about how reports are canceled, see [Report Generation and Cancellation Flow](report-cancellation.md).

Default: MaxValue
Dynamically Updatable: Yes| | Report PDF Font Embedding |ReportPDFFontEmbedding| Specifies whether fonts are embedded in PDF files that are generated for reports when the report uses an RDLC report layout at runtime. This setting applies when reports are run and saved as PDF files on the client (from the report request page or print preview window) or on the server instance (by the [SAVEAS function](../developer/methods/devenv-SAVEAS-method.md) or [SAVEASPDF function](../developer/methods/devenv-SAVEASPDF-method-Report.md) in AL code).

**Note:** This setting doesn't apply when a report uses a Word report layout at runtime.

You embed fonts in a PDF of a report to make sure that the PDF will use the same fonts as the original file, no matter where the PDF is opened and which fonts are installed on the computer. However, embedding fonts can significantly increase the size of the PDF files. Disabling font embedding decreases the size of the report PDF files.

**Note:** This setting is a global setting for font embedding in report PDF files. You can override this setting on a report basis by the specifying the [PDFFontEmbedding property](../developer/properties/devenv-PDFFontEmbedding-Property.md).

Default: Enabled
Dynamically Updatable: No| From 2ef05d95299a0b9edfa0741c46c0e76219ddca58 Mon Sep 17 00:00:00 2001 From: Mike Borg Cardona Date: Fri, 7 Aug 2020 18:08:44 +0200 Subject: [PATCH 107/950] Update performance-users.md --- dev-itpro/performance/performance-users.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dev-itpro/performance/performance-users.md b/dev-itpro/performance/performance-users.md index 005f65fabd..47df5d0194 100644 --- a/dev-itpro/performance/performance-users.md +++ b/dev-itpro/performance/performance-users.md @@ -2,7 +2,7 @@ title: Performance Tips for Business Users description: Various tips and tricks to improve speed and agility of working with Business Central. ms.custom: na -ms.date: 04/01/2020 +ms.date: 08/07/2020 ms.reviewer: solsen ms.suite: na ms.tgt_pltfrm: na @@ -23,7 +23,8 @@ This section describes how you can work with end-users to improve the performanc - Where possible, avoid older browsers such as Internet Explorer, and switch to one of our recommended modern browsers, such as the [new Microsoft Edge](https://www.microsoft.com/edge/). Internet Explorer is still supported, but since the new Edge browser is available for Windows Server now, we see a declining rate of usage for Internet Explorer. You can also get [a pilot of Edge in IE mode](https://www.microsoft.com/edge/business). For more information, see [Microsoft Edge documentation](/deployedge/edge-ie-mode). -- Keep your browser always updated to the latest version. +- Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] performance features and optimizations are only available for modern browsers. +- Keep your browser always updated to the latest version which may include the latest performance enhancements. ## Choosing a network connection @@ -42,7 +43,13 @@ In order to provide an optimal experience, Business Central saves some preferenc - List pages load records in small batches while the user scrolls through the list, allowing it to scale to very large tables. - The overall structure of a page (but not business data) is cached on the client device after a page is accessed the first time. -The time taken to load any page is also affected by the number of controls on the page. Users can improve performance on complex pages using these methods: +To take full advantage of page caching, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] requires a modern browser with access to the browser's storage mechanisms. Any browser settings that restrict access to local storage or the browser's IndexedDB may prevent [!INCLUDE[prodshort](../developer/includes/prodshort.md)] from applying performance optimizations. + +> [!IMPORTANT] +> Browsers that run in private or guest mode typically discard browser storage when the browser window is closed. This discards cached data and users will not be able to take advantage of page caching when they next sign into [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. Users relying on private or guest browsing to work with multiple identities or [!INCLUDE[prodshort](../developer/includes/prodshort.md)] organizations are advised to use browser profiles instead. + + +The time taken to load any page is also affected by the number of controls shown on the page. Users can improve performance on complex pages using these methods: - By *collapsing* secondary content that may be needed only occasionally. For example, when the FactBox pane on a page is collapsed, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] saves time from attempting to display all the related facts. - By *hiding* secondary content entirely from the page. For example, hiding Role Center parts or columns that are not used by the user, department or organization will also improve the time needed to load the page. Learn more about [Personalizing Your Workspace](/dynamics365/business-central/ui-personalization-user). From d58f8f723193b9886d91033fe4a36d6541f353e8 Mon Sep 17 00:00:00 2001 From: jswymer Date: Sun, 9 Aug 2020 10:38:56 +0200 Subject: [PATCH 108/950] Update devenv-adding-a-factbox-to-page.md --- .../developer/devenv-adding-a-factbox-to-page.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md index 85865ac30b..24253ddd22 100644 --- a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md +++ b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md @@ -131,16 +131,16 @@ page 50101 "Simple Customerlist Page" Having a page composed of multiple FactBox pages that each process data from different sources can degrade performance. To improve responsiveness and the time it takes to load the page, [!INCLUDE[prodshort](includes/prodshort.md)] 2020 release wave 2 and later optimizes the sequence in which content is loaded. The sequence is as follows: -1. Content on the hosting page is loaded first and users can immediately begin interacting with it. -2. The FactBox pane is loaded next where each FactBox is loaded independently in sequence starting from the top. - 1. FactBoxes having the `Visible` property evaluate to `false` will not be loaded. - 2. FactBoxes that are not within view are only loaded when the user scrolls them into view. +1. Content on the hosting page is loaded first, and users can immediately begin interacting with it. +2. The FactBox pane is loaded next, where each FactBox is loaded independently in sequence starting from the top. + 1. FactBoxes having the `Visible` property evaluate to `false` won't be loaded. + 2. FactBoxes that aren't within view are only loaded when the user scrolls them into view. If the FactBox pane is collapsed, no FactBoxes are loaded until the user expands the FactBox pane. -Below are some practical tips to help you make the most out of this optimization: - - Consider hiding any FactBoxes that represent secondary content which only some users will require. Learn more about [Choosing the Visibility of Parts](devenv-designing-parts#choosing-the-visibility-of-parts). - - Consider processing in the background for FactBoxes that require heavy processing. Learn more about [Using Page Background Tasks](devenv-designing-parts#using-page-background-tasks). - - Avoid having triggers on the hosting page that call into a FactBox as this forces the FactBox to ignore performance optimizations and load along with the content of the hosting page, adding to the total loading time. +Below are some practical tips to help you make the most of this optimization: + - Consider hiding any FactBoxes that represent secondary content that only some users will require. Learn more about [Choosing the Visibility of Parts](devenv-designing-parts.md#choosing-the-visibility-of-parts). + - For FactBoxes that require heavy processing, consider processing in the page background task. Learn more about [Using Page Background Tasks](devenv-designing-parts.md#using-page-background-tasks). + - Avoid having triggers on the hosting page that call into a FactBox because this condition forces the FactBox to ignore performance optimizations and load along with the content of the hosting page, adding to the total loading time. ### FAQ about performance From fba884be0f38f1f2640b765129c7f7e1880c20c0 Mon Sep 17 00:00:00 2001 From: jswymer Date: Mon, 10 Aug 2020 08:53:51 +0200 Subject: [PATCH 109/950] Update devenv-adding-a-factbox-to-page.md --- .../devenv-adding-a-factbox-to-page.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md index 24253ddd22..43806efc7c 100644 --- a/dev-itpro/developer/devenv-adding-a-factbox-to-page.md +++ b/dev-itpro/developer/devenv-adding-a-factbox-to-page.md @@ -144,25 +144,25 @@ Below are some practical tips to help you make the most of this optimization: ### FAQ about performance -#### Are any FactBox triggers executed when the FactBox is hidden? -No. The trigger is only run once the FactBox is visible and within the user's view. +#### Are any FactBox triggers run when the FactBox is hidden? +No. The trigger is only run when the FactBox is visible and within the user's view. -#### How often are triggers executed if the FactBox pane is expanded, collapsed and then expanded again? -In this scenario, the `OnOpenPage` trigger is only run the first time. Once a FactBox is loaded, it is not loaded again for as long as the page remains open. +#### How often are triggers run if the FactBox pane is expanded, collapsed, and then expanded again? +In this scenario, the `OnOpenPage` trigger is only run the first time. Once a FactBox is loaded, it isn't loaded again for as long as the page remains open. #### Are FactBoxes processed asynchronously? -No. This optimization is simply a controlled sequence in which triggers are executed, still within the same session as the hosting page. For more information about asynchronous processing in the background, see [Designing page parts for page background tasks](devenv-page-background-tasks#partpages). +No. This optimization is simply a controlled sequence in which triggers are run, still within the same session as the hosting page. For more information about asynchronous processing in the background, see [Designing page parts for page background tasks](devenv-page-background-tasks.md#partpages). -#### Does this work with SubPageLink or SubPageView properties? +#### Does this optimization work with SubPageLink or SubPageView properties? The use of these properties has no effect on the sequence of loading content on a page. Using properties such as `SubPageView` is preferred to writing trigger code to update a FactBox. -#### Does this optimization apply to parts that are not FactBoxes? -This optimization does not apply to Role Center pages. When parts are used in the content area of a page, such as on a Card page, they are not loaded if their `Visible` property evaluates to `false`. +#### Does this optimization apply to parts that aren't FactBoxes? +This optimization doesn't apply to Role Center pages. When parts are used in the content area of a page, such as on a Card page, they aren't loaded if their `Visible` property evaluates to `false`. #### Can I force a FactBox to load along with page content? -There is no AL API to force FactBoxes to load along with the content of the hosting page. +There's no AL API to force FactBoxes to load along with the content of the hosting page. -#### Can i set the FactBox pane to start collapsed on all pages? +#### Can I set the FactBox pane to start collapsed on all pages? No. The default state of the FactBox pane is set by the [!INCLUDE[prodshort](includes/prodshort.md)] platform and modifed by the user. #### Does the experience vary on different browsers? From 2b0a7a1946a9e0f61d9fdc5fc69b0809d04bc543 Mon Sep 17 00:00:00 2001 From: jswymer Date: Tue, 11 Aug 2020 19:44:40 +0200 Subject: [PATCH 110/950] Update setup-app-key-vault.md --- dev-itpro/administration/setup-app-key-vault.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/administration/setup-app-key-vault.md b/dev-itpro/administration/setup-app-key-vault.md index 2d34eab41c..6fb2fd0a50 100644 --- a/dev-itpro/administration/setup-app-key-vault.md +++ b/dev-itpro/administration/setup-app-key-vault.md @@ -12,7 +12,7 @@ author: jswymer --- # Setting up App Key Vaults for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online -AppsSource apps for [prodshort](../developer/includes/prodshort.md)] can be developed to get secrets from Azure Keys Vaults. The app key feature is readily available for use on the service by all App Source apps. However, there are some onboarding tasks required. +AppsSource apps for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] can be developed to get secrets from Azure Keys Vaults. The app key feature is readily available for use on the service by all App Source apps. However, there are some onboarding tasks required. ## Create the Azure Key Vault with secrets From 8e0c4dc3c459caa8b3f46ad0442264f4773b83f1 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 08:40:55 +0200 Subject: [PATCH 111/950] Update telemetry-overview.md --- dev-itpro/administration/telemetry-overview.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index e92eb45265..7e83e61aa9 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -38,12 +38,13 @@ In Application Insights, telemetry from [!INCLUDE[prodshort](../developer/includ ## Enabling Application Insights -Sending telemetry data to Application Insights requires you have an Application Insights resource in Azure. Once you have the Application Insights resource, you can start to configure your tenants to send telemetry data to your Application Insights resource. The configuration is different for Online and On-premises: - +Sending telemetry data to Application Insights requires you have an Application Insights resource in Azure. Once you have the Application Insights resource, you can start to configure your tenants and extensions to send telemetry data to your Application Insights resource. The configuration is different for Online and On-premises: + - For [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Online, Application Insights is enabled by using the Administration Center. For more information, see [Enable Sending Telemetry to Application Insights](tenant-admin-center-telemetry.md#appinsights). - For [!INCLUDE[prodshort](../developer/includes/prodshort.md)] On-premises, see [Enable Sending Telemetry to Application Insights](telemetry-enable-application-insights.md). +- ## Viewing telemetry data in Application Insights Telemetry from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is stored in Azure Monitor Logs in the *traces* table. You can view collected data by writing log queries. Log queries are written in the Kusto query language (KQL). For more information, see [Logs in Azure Monitor](/azure/azure-monitor/platform/data-platform-logs) and [Overview of log queries in Azure Monitor](/azure/azure-monitor/log-query/log-query-overview). From f1202b78b2eef98ecaf12767faea46c732223461 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 09:22:51 +0200 Subject: [PATCH 112/950] Update telemetry-overview.md --- .../administration/telemetry-overview.md | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 7e83e61aa9..6b158ece45 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -16,25 +16,31 @@ ms.author: jswymer [!INCLUDE[2019_releasewave2.md](../includes/2019_releasewave2.md)] -[!INCLUDE[prodshort](../developer/includes/prodshort.md)] emits telemetry data for various activities and operations on tenants. Whether running [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Online or On-premises, you can set up your tenants to send telemetry to Application Insights. Application Insights is a service hosted within Azure that gathers telemetry data for analysis and presentation. For more information, see [What is Application Insights?](/azure/azure-monitor/app/app-insights-overview). +[!INCLUDE[prodshort](../developer/includes/prodshort.md)] emits telemetry data for various activities and operations on tenants and extensions. Whether running [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Online or On-premises, you can set up your tenants to send telemetry to Application Insights. Application Insights is a service hosted within Azure that gathers telemetry data for analysis and presentation. For more information, see [What is Application Insights?](/azure/azure-monitor/app/app-insights-overview). Monitoring telemetry gives you a look at the activities and general health of your tenants. It helps you diagnose problems and analyze operations that affect performance. + + +## Service-level and extension-level telemetry + +Application Insights can be enabled on two different levels: service and extension. When enabled on the service, either for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online tenant or on-premises [!INCLUDE[server](../developer/includes/server.md)] instance, telemetry is emitted to a single Application Insights resource for gathering data tenant-wide operations. + +It can also be enabled a per-extension basis. An Application Insights key is set in the extension's manifest (app.json file). At runtime, certain events related to the extension are emitted to the Application Insights resource. This feature targets publishers of per-tenant extensions to get insight into issues in their extension before partners and customers report them. -Monitoring telemetry gives you a look at the activities and general health of your tenants. It helps you diagnose problems and analyze operations that affect performance. ## Available telemetry In Application Insights, telemetry from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is logged as traces. Currently, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] offers telemetry on the following operations: -|Area | Description |Online/On-premises|See more| -|----------|-------------|-----------------|--------| -|Authorization|Provides information about user sign-in attempts. Information includes success or failure indication, reason for failure, user type, and more.|Online|[Analyzing Authentication Telemetry](telemetry-authorization-trace.md) | -|Company lifecycle|Provides information about creating, copying, and deleting of companies.|Both|[Analyzing Company Lifecycle Telemetry](telemetry-company-lifecycle-trace.md) | -|Database lock timeouts|Provides information about database locks that have timed out. |Both|[Database Lock Timeout Telemetry](telemetry-database-locks-trace.md)| -|Extension lifecycle|Provides information about the success or failure of extension-related operations, like publishing, synchronizing, installing, and more.|Both|[Analyzing Extension Lifecycle Telemetry](telemetry-extension-lifecycle-trace.md) | -|Extension update|Provides information about errors that occur when upgrading an extension.|Both|[Analyzing Extension Upgrade Telemetry](telemetry-extension-update-trace.md) | -|Long running operation (SQL query)|Provides information about SQL queries that take longer than expected to execute.|Both|[Analyzing Long Running Operation (SQL Query) Telemetry](telemetry-long-running-sql-query-trace.md)| -|Page views|Provides information about the pages that users open in the modern client.|Online|[Analyzing Page View Telemetry](telemetry-page-view-trace.md)| -|Report generation|Provides information about the execution of reports.|Both|[Analyzing Report Generation Telemetry](telemetry-reports-trace.md)| -|Web service requests|Provides information about the execution time of web service requests.|Both|[Analyzing Web Service Requests Telemetry](telemetry-webservices-trace.md)| +|Area | Description |Online/On-premises|Extension|See more| +|-----|-------------|------------------|---------|--------| +|Authorization|Provides information about user sign-in attempts. Information includes success or failure indication, reason for failure, user type, and more.|Online|No|[Analyzing Authentication Telemetry](telemetry-authorization-trace.md) | +|Company lifecycle|Provides information about creating, copying, and deleting of companies.|Both|No|[Analyzing Company Lifecycle Telemetry](telemetry-company-lifecycle-trace.md) | +|Database lock timeouts|Provides information about database locks that have timed out. |Both|No|[Database Lock Timeout Telemetry](telemetry-database-locks-trace.md)| +|Extension lifecycle|Provides information about the success or failure of extension-related operations, like publishing, synchronizing, installing, and more.|Both|No|[Analyzing Extension Lifecycle Telemetry](telemetry-extension-lifecycle-trace.md) | +|Extension update|Provides information about errors that occur when upgrading an extension.|Both|Yes|[Analyzing Extension Upgrade Telemetry](telemetry-extension-update-trace.md) | +|Long running operation (SQL query)|Provides information about SQL queries that take longer than expected to execute.|Both|Yes|[Analyzing Long Running Operation (SQL Query) Telemetry](telemetry-long-running-sql-query-trace.md)| +|Page views|Provides information about the pages that users open in the modern client.|Online|No|[Analyzing Page View Telemetry](telemetry-page-view-trace.md)| +|Report generation|Provides information about the execution of reports.|Both|Yes|[Analyzing Report Generation Telemetry](telemetry-reports-trace.md)| +|Web service requests|Provides information about the execution time of web service requests.|Both|Yes|[Analyzing Web Service Requests Telemetry](telemetry-webservices-trace.md)| ## Enabling Application Insights @@ -44,7 +50,7 @@ Sending telemetry data to Application Insights requires you have an Application - For [!INCLUDE[prodshort](../developer/includes/prodshort.md)] On-premises, see [Enable Sending Telemetry to Application Insights](telemetry-enable-application-insights.md). -- +- For extensions, see [] ## Viewing telemetry data in Application Insights Telemetry from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is stored in Azure Monitor Logs in the *traces* table. You can view collected data by writing log queries. Log queries are written in the Kusto query language (KQL). For more information, see [Logs in Azure Monitor](/azure/azure-monitor/platform/data-platform-logs) and [Overview of log queries in Azure Monitor](/azure/azure-monitor/log-query/log-query-overview). From 2de8974729d037209dcf70cce41fb928448a849f Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 09:37:41 +0200 Subject: [PATCH 113/950] Update telemetry-overview.md --- dev-itpro/administration/telemetry-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 6b158ece45..684855186e 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -30,7 +30,7 @@ It can also be enabled a per-extension basis. An Application Insights key is set In Application Insights, telemetry from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is logged as traces. Currently, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] offers telemetry on the following operations: -|Area | Description |Online/On-premises|Extension|See more| +|Area | Description |Online/On-premises|Extension support|See more| |-----|-------------|------------------|---------|--------| |Authorization|Provides information about user sign-in attempts. Information includes success or failure indication, reason for failure, user type, and more.|Online|No|[Analyzing Authentication Telemetry](telemetry-authorization-trace.md) | |Company lifecycle|Provides information about creating, copying, and deleting of companies.|Both|No|[Analyzing Company Lifecycle Telemetry](telemetry-company-lifecycle-trace.md) | From 1c35e33b58d014c4686e56102344452aea028ec7 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Wed, 12 Aug 2020 11:58:36 +0200 Subject: [PATCH 114/950] porting topics --- dev-itpro/powerplatform/admin-reference.md | 172 ++++++++++++++ .../application-lifecycle-management.md | 77 ++++++ dev-itpro/powerplatform/entity-modeling.md | 224 ++++++++++++++++++ dev-itpro/powerplatform/faq.md | 110 +++++++++ dev-itpro/powerplatform/overview.md | 64 +++++ .../powerplatform/power-portal-reference.md | 53 +++++ 6 files changed, 700 insertions(+) create mode 100644 dev-itpro/powerplatform/admin-reference.md create mode 100644 dev-itpro/powerplatform/application-lifecycle-management.md create mode 100644 dev-itpro/powerplatform/entity-modeling.md create mode 100644 dev-itpro/powerplatform/faq.md create mode 100644 dev-itpro/powerplatform/overview.md create mode 100644 dev-itpro/powerplatform/power-portal-reference.md diff --git a/dev-itpro/powerplatform/admin-reference.md b/dev-itpro/powerplatform/admin-reference.md new file mode 100644 index 0000000000..8f4435c202 --- /dev/null +++ b/dev-itpro/powerplatform/admin-reference.md @@ -0,0 +1,172 @@ +--- +# required metadata + +title: Finance and Operations and Common Data Service admin reference +description: This topic covers set up and configuration of virtual entities for Finance and Operations. +author: Sunil-Garg +manager: AnnBe +ms.date: 07/13/2020 +ms.topic: article +ms.prod: +ms.service: dynamics-ax-applications +ms.technology: + +# optional metadata + +# ms.search.form: +audience: Developer, IT Pro +# ms.devlang: +ms.reviewer: sericks +ms.search.scope: Operations +# ms.tgt_pltfrm: +# ms.custom: NotInToc +ms.search.region: Global +# ms.search.industry: +ms.author: sunilg +ms.search.validFrom: 2020-05-31 +ms.dyn365.ops.version: 10.0.12 +--- + +# Finance and Operations and Common Data Service admin reference +[!include[banner](../includes/banner.md)] + +> [!IMPORTANT] +> This functionality requires [Platform updates for version 10.0.12 of Finance and Operations apps](../get-started/whats-new-platform-update-10-0-12.md) and service update 189 for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). + +This topic provides step-by-step instructions about how to set up and configure virtual entities for Finance and Operations apps in Common Data Service. + +## Getting the solution +The Common Data Service solution for Finance and Operations virtual entities must be installed from Microsoft AppSource virtual entity solution. For more information, see [Finance and Operations virtual entity](https://appsource.microsoft.com/product/dynamics-crm/mscrm.finance_and_operations_virtual_entity). + +Ensure the following solutions are installed in Common Data Service. These solutions must be extracted from the downloaded package. + +- **Dynamics365Company** - This adds the **Company** entity, which is referenced by all Finance and Operations entities with a PrimaryCompanyContext metadata value. + +- **MicrosoftOperationsVESupport** - This provides the core support for the Finance and Operations virtual entity feature. + +- **MicrosoftOperationsERPCatalog** - This provides a list of available Finance and Operations entities through the mserp_financeandoperationsentity virtual entity. + +- **MicrosoftOperationsERPVE** - This is the API-managed solution, which will contain the generated virtual entities as they are made visible. + +## Authentication and authorization + +After the solutions are imported in the Common Data Service environment, both environments must be set up to connect to each other. Common Data Service will call Finance and Operations using Service-to-Service (S2S) authentication, based on an Azure Active Directory (AAD) application. This new AAD application represents the single instance of the Common Data Service environment. If you have multiple pairs of Common Data Service and Finance and Operations environments, separate AAD applications for each pair must be created to ensure connections are established between the correct pair of Finance and Operations and Common Data Service environments. The following procedure shows the creation of the AAD application. + +> [!IMPORTANT] +> The AAD application must be created on the same tenant as Finance and Operations. + +1. Go to **\> Azure Active Directory \> App registrations**. + +2. Select **New Registration**. Enter the following information: + + - **Name** - Enter a unique name. + + - **Account type** - Enter **Any Azure AD directory** (single or multi-tenant). + + - **Redirect URI** - Leave blank. + + - Select **Register**. + + - Make note of the **Application (client) ID** value, you will need it later. + +3. Create a symmetric key for the application. + + - Select **Certificates & secrets** in the newly created application. + + - Select **New client secret**. + + - Provide a description and an expiration date. + + - Select **Save**. A key will be created and displayed. Copy this value for later use. + +The AAD application created above will be used by Common Data Service to call Finance and Operations apps. As such, it must be trusted by Finance and Operations and associated with a user account with the appropriate rights in Finance and Operations. A special service user must be created in Finance and Operations with rights *only* to the virtual entity functionality, and no other rights. After completing this step, any application with the secret of the AAD application create above will be able to call this Finance and Operations environment and access the virtual entity functionality. + +The next steps walk through this process in Finance and Operations apps. + +1. In Finance and Operations, go to **System Administration \> Users \> Users**. + +2. Select **New** to add a new user. Enter the following information: + + - **User ID** - Enter **cdsintegration** (or a different value). + + - **User name** - Enter **cds integration** (or a different value). + + - **Provider** - Leave at the default value. + + - **Email** - Enter **cdsintegration** (or a different value, does *not* need to be a valid email account). + + - Assign the security role **CDS virtual entity application** to this user. + + - Remove all other roles including **System user**. + +3. Go to **System Administration \> Setup \> Azure Active Directory applications** to register Common Data Service. + + - Add a new row. + + - **Client ID** - The **Application (client) ID** created above + + - **Name** - Enter **CDS Integration** (or a different name). + + - **User ID** - The user ID created above. + +The next step in the process is to provide Common Data Service with the Finance and Operations instance to connect to. The following steps walk through this part of the process. + +1. In Common Data Service, go to **Advanced Settings \> Administration \> Virtual Entity Data Sources**. + +2. Select the data source named “Finance and Operations”. + +3. Fill in the information from the steps above. + + - **Target URL** - The URL at which you can access Finance and Operations. + + - **OAuth URL** - https://login.windows.net/ + + - **Tenant ID** - Your tenant, such as “contoso.com”. + + - **AAD Application ID** - The **Application (client) ID** created above. + + - **AAD Application Secret** - The secret generated above. + + - **AAD Resource** - Enter 00000015-0000-0000-c000-000000000000 (this is the AAD application representing Finance and Operations, and should always be this same value). + +4. Save the changes. + +## Enabling virtual entities + +Due to the large number of OData enabled entities available in Finance and Operations, by default, the entities are not available as virtual entities in Common Data Service. The following steps allow for enabling entities to be virtual, as needed. + +1. In Common Data Service, go to **Advanced find**. + +2. Look for “Available Finance and Operations Entities” and select **Results**. + +![Catalog](../media/fovecatalog.png) + +3. Locate and open the entity that you want to enable. + +4. Set **Visible** to **Yes** and save. This will generate the virtual entity, so that it will appear in all of the appropriate menus, such as the advanced find dialog box. + +![Enable VE](../media/foveenable.png) + +## Refreshing virtual entity metadata + +The virtual entity metadata can be force-refreshed when it is expected for the entity metadata in Finance and Operations to have changed. This can be done by setting **Refresh** to **Yes** and saving. This will sync the latest entity definition from Finance and Operations to Common Data Service and update the virtual entity. + +Referencing virtual entities +---------------------------- + +The virtual entities are all generated in the MicrosoftOperationsERPVE solution, which is API Managed. That means the items in the solution change as you make entities visible/hidden, but it is still a managed solution that you can take dependency on. The standard ALM flow would be to just take a standard reference to a virtual entity from this solution with the **Add existing** option +in the ISV solution. It will then show as a missing dependency of the solution and be checked at solution import time. During import if a specified virtual entity does not yet exist, it would automatically be made visible without needing additional work. + +To consume virtual entities: + +1. Create a separate solution as usual in Common Data Service, which will contain the consuming logic. + +2. Select **Entities \> Add Existing**. Select the virtual entity that you want to reference from the list. + +3. When prompted to select assets to add, select any forms, views, or other elements that you want to customize, then select **Finish**. + +From the development tooling, existing elements such as forms can be modified for the virtual entity. Additionally, new forms, views, and other elements can also be added. + +![Solution](../media/fovesolution.png) + +When the solution is exported, it will contain hard dependencies on the virtual entity generated in the MicrosoftOperationsERPVE solution. diff --git a/dev-itpro/powerplatform/application-lifecycle-management.md b/dev-itpro/powerplatform/application-lifecycle-management.md new file mode 100644 index 0000000000..c9bd1f8ce2 --- /dev/null +++ b/dev-itpro/powerplatform/application-lifecycle-management.md @@ -0,0 +1,77 @@ +--- +# required metadata + +title: Application lifecycle management for solutions that use virtual entities +description: This topic explains the application lifecycle for solutions that use virtual entities for Finance and Operations. +author: Sunil-Garg +manager: AnnBe +ms.date: 07/13/2020 +ms.topic: article +ms.prod: +ms.service: dynamics-ax-applications +ms.technology: + +# optional metadata + +# ms.search.form: +audience: Developer, IT Pro +# ms.devlang: +ms.reviewer: sericks +ms.search.scope: Operations +# ms.tgt_pltfrm: +# ms.custom: NotInToc +ms.search.region: Global +# ms.search.industry: +ms.author: sunilg +ms.search.validFrom: 2020-10-31 +ms.dyn365.ops.version: 10.0.0 +--- + +# Application lifecycle management for solutions that use virtual entities + +[!include[banner](../includes/banner.md)] + +> [!IMPORTANT] +> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). + +The application lifecycle for an end-to-end solution using Finance and Operations virtual entities will encompass both Finance and Operations as well as Common Data Service. This topic explains this in detail. + +## Solution management + +Virtual entities for Finance and Operations don't exist in Common Data Service until they are created. Virtual entities must be created inside a solution. The MicrosoftOperationsERPVE solution is used for this purpose. This solution will contain all the virtual entities that are created from an instance of Finance and Operations. + +MicrosoftOperationsERPVE is a [managed solution](https://docs.microsoft.com/powerapps/developer/common-data-service/introduction-solutions). By definition, a managed solution can't be modified after it has been generated. However, MicrosoftOperationsERPVE is a managed solution that grants privileges to update the components (that is, virtual entities) that are inside it. Therefore, new virtual entities can be added to the solution as they are created, and existing virtual entities can be updated as required. Nevertheless, the privileges to modify the managed solution are available only to the platform itself. Users can't make changes directly to the solution. + +Because MicrosoftOperationsERPVE is a managed solution, solutions from customers, partners, and independent software vendors (ISVs) can take a dependency on it. This capability allows for consistent application lifecycle management (ALM) for solutions that use and depend on the virtual entities for Finance and Operations. + +When a solution that depends on MicrosoftOperationsERPVE is exported, placeholders for the virtual entities that are used in the solution are added in the exported solution. When that solution is imported into another Common Data Service environment, the import process also generates the dependent Finance and Operations virtual entities in the MicrosoftOperationsERPVE solution for the Finance and Operations instance that is connected to the Common Data Service environment. Therefore, MicrosoftOperationsERPVE must already exist before a solution that depends on it is imported. Otherwise, an error message is shown. Additionally, if a dependent entity isn't available in the Finance and Operations instance, the virtual entity for that entity won't be generated. Virtual entities are generated only for entities that are available. + +The following list describes other solutions that Finance and Operations virtual entities require to work, and that must be available in the Common Data Service environment: + +- **MicrosoftOperationsERPCatalog** – This solution provides a catalog of the available entities in a Finance and Operations instance. It also provides the connection that is used to set up a configuration. For more information, see the later sections of this topic. +- **MicrosoftOperationsVESupport** – This solution provides the virtual entity provider for Finance and Operations apps. The provider can communicate with Finance and Operations apps and Common Data Service. For more information, see the next section. +- **Dynamics365Company** – This solution adds the Company entity, which is referenced by all Finance and Operations entities that have a **PrimaryCompanyContext** metadata value. + +All these solutions must be present in an environment. Otherwise, virtual entities won't work with Finance and Operations apps. These solutions are packaged together to allow for easier portability across environments. + +## Managing entities from multiple environments + +The MicrosoftOperationsVESupport solution consists of the **msdyn\_financeandoperationsvirtualentity** entity. This entity represents the virtual entity data source for Finance and Operations that captures connection setup information. Each record in this entity represents a connection to a Finance and Operations instance. + +A catalog is used to list all the entities in a Finance and Operations instance that are available for virtualization in Common Data Service (in other words, all the entities in Finance and Operations that are enabled for Open Data Protocol \[OData\]). The catalog is part of the default MicrosoftOperationsERPCatalog solution and is applicable to a Finance and Operations instance. + +Note that each Common Data Service environment must point to only one Finance and Operations instance at any time, and each Finance and Operations environment must point to only one Common Data Service environment. Therefore, there should be only one record in the **msdyn\_financeandoperationsvirtualentity** entity. + +The **mserp\_financeandoperationsentity** entity that represents the catalog can be queried to list the entities in a Finance and Operations instance. Because this entity is a virtual entity, the catalog is never persisted in Common Data Service. + +Notice that the name of the catalog entity has the "mserp\_" prefix. This prefix identifies the entities in the catalog as Finance and Operations entities. The same prefix is also added to the system names of the virtual entities that are generated for Finance and Operations in the MicrosoftOperationsERPVE solution. Therefore, the maker can distinguish Finance and Operations virtual entities from other entities. The prefix is set in the managed solution and can't be changed. + +### Managing entities from multiple ISV solutions + +One or more ISV solutions will take a dependency on the MicrosoftOperationsERPVE solution to use virtual entities for Finance and Operations. Because custom entities in Finance and Operations use the same catalog as out-of-box entities in Finance and Operations, the virtual entities for custom Finance and Operations entities will also be generated in the MicrosoftOperationsERPVE solution. + +The established guidelines and ALM for entity development in Finance and Operations ensure that there are no conflicting entity names across ISV solutions. Therefore, no conflicts of this type can occur when virtual entities are generated in Common Data Service for custom Finance and Operations entities from multiple ISV solutions. All virtual entities for Finance and Operations entities, including custom entities, will have the "mserp\_" prefix that was mentioned earlier. + +### Managing a Finance and Operation instance in a Common Data Service environment for virtual entities + +One Finance and Operations instance must be linked to a Common Data Service environment for virtual entities. The connection setup information that is required is captured in a virtual entity data source for Finance and Operations. This data source is included in the MicrosoftOperationsERPCatalog solution. diff --git a/dev-itpro/powerplatform/entity-modeling.md b/dev-itpro/powerplatform/entity-modeling.md new file mode 100644 index 0000000000..41f4d9824e --- /dev/null +++ b/dev-itpro/powerplatform/entity-modeling.md @@ -0,0 +1,224 @@ +--- +# required metadata + +title: Entity modeling +description: This topic explains relational modeling concepts using virtual entities for Finance and Operations entities. +author: Sunil-Garg +manager: AnnBe +ms.date: 07/21/2020 +ms.topic: article +ms.prod: +ms.service: dynamics-ax-applications +ms.technology: + +# optional metadata + +# ms.search.form: +audience: Developer, IT Pro +# ms.devlang: +ms.reviewer: sericks +ms.search.scope: Operations +# ms.tgt_pltfrm: +# ms.custom: NotInToc +ms.search.region: Global +# ms.search.industry: +ms.author: sunilg +ms.search.validFrom: 2020-05-31 +ms.dyn365.ops.version: 10.0.12 +--- + +# Entity modeling + +[!include[banner](../includes/banner.md)] + +> [!IMPORTANT] +> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). + +> The public entity name that is exposed in Common Data Service metadata for the Finance and Operations virtual entity uses the physical name of the Finance and Operations entity. This could be different from the public name of the entity as exposed by the OData metadata in Finance and Operations apps. + +Building an app requires capabilities to perform relational modeling between entities that are being used in the app. In the context of virtual entities, there will be scenarios where virtual entities and native entities in Common Data Service must work together to enable the desired user experience. This topic explains concepts of relational modeling that can be implemented using virtual entities for Finance and Operations. + +## Generating virtual entities + +By default, virtual entities for Finance and Operations apps don't exist in Common Data Service. A user must query the catalog entity to view the entities that are available in the linked instance of Finance and Operations. From the catalog, the user can select one or more entities, and then request that Common Data Service generate the virtual entities. This procedure is explained in later sections. + +## Entity fields + +When a virtual entity is generated for a Finance and Operations entity, the system tries to create each field in the Finance and Operations entity in the corresponding virtual entity in Common Data Service. In an ideal case, the total number of fields will be the same in both entities, unless there is a mismatch in supported data types between Finance and Operations and Common Data Service. For data types that are supported, the field properties in Common Data Service are set based on the properties in Finance and Operations. + +This rest of this section describes supported and unsupported data types. For more information about fields in Common Data Service, see [Fields overview](https://docs.microsoft.com/powerapps/maker/common-data-service/fields-overview). + +| Data type in Finance and Operations | Modeled data type in Common Data Service | +|-------------------------------------|------------------------------------------| +| Real | Decimal

For information about the possible mismatch, see the next table.

| +| Long | Decimal, where the precision equals 0 (zero) | +| Int | Integer | +| String (non-memo), String (memo) | String – single line of text, String – multiple lines of text | +| UtcDateTime | DateTime (DateTimeFormat.DateAndTime, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Finance and Operations is surfaced as a null value in Common Data Service. | +| Date | DateTime - (DateTimeFormat.DateOnly, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Finance and Operations is surfaced as an empty value in Common Data Service. | +| Enum | Picklist

Finance and Operations enumerations (enums) are generated as global OptionSets in Common Data Service. Matching between the systems is done by using the **External Name** property of values. Enum integer values in Common Data Service aren't guaranteed to be stable between the systems. Therefore, you should not rely on them, especially in the case of extensible enums in Finance and Operations, because these enums don't have a stable ID either. OptionSet metadata is updated when an entity that uses the OptionSet is updated. | + +Fields of the *real* and *long* data types in Finance and Operations are modeled as the *decimal* data type in Common Data Service. Because of the mismatch in precision and scale between the two data types, the following behavior must be considered. + +| Use case | Resulting behavior | +|----------------------------------------------|--------------------| +| Common Data Service has higher precision. | This use case should never occur unless the metadata is out of sync. | +| Finance and Operations has higher precision. | During a read operation, the value is rounded to the closest precision value in Common Data Service. If the value is edited in Common Data Service, it's rounded to the closest precision value in Finance and Operations. During a write operation, the value that is specified in Common Data Service is written, because Finance and Operations supports higher precision. | +| Common Data Service has higher scale. | Not applicable | +| Finance and Operations has higher scale. | Common Data Service shows the Finance and Operations value, even if it exceeds 100 billion. However, there will be a loss of precision. For example, 987,654,100,000,000,000 is shown in Common Data Service as "987,654,099,999,999,900". If the value of this field is edited in Common Data Service, Common Data Service validation throws an error that the value exceeds the maximum value before that value is sent to Finance and Operations. | + +The following data types in Finance and Operations aren't supported in Common Data Service. Fields of these data types in Finance and Operations entities won't be made available in the corresponding virtual entities in Common Data Service. If fields of these data types are used as parameters in Open Data Protocol (OData) actions, those actions won't be available for use in the corresponding virtual entities. For more information about OData actions, see the [OData actions](#odata-actions) section later in this topic. + +- AnyType +- BLOB +- Class +- Container +- Guid +- Record +- Time +- UserType +- VarArg +- Void (Void return types on OData actions are supported.) + +Data type that are supported in Common Data Service but not in Finance and Operations aren't supported in virtual entities for Finance and Operations. + +## Entity key/primary key + +In Finance and Operations, entities can have one or more fields of various data types as the entity key. An entity key uniquely identifies a record in a Finance and Operations entity. Additionally, a record in an entity can be uniquely identified by a record ID primary key of the Int64 type. + +In Common Data Service, the primary key is always a globally unique identifier (GUID). The GUID-based primary key enables a record in an entity in Common Data Service to be uniquely identified. + +To bridge the implementation gap between Finance and Operations and Common Data Service, the primary key of a virtual entity for Finance and Operations is a GUID (to comply with Common Data Service). This GUID consists of the data entity ID in the first 4 bytes, and the record ID of the root data source in the entity as the last 8 bytes. This design satisfies Common Data Service's requirement that a GUID be used as the entity key. It also enables the table ID and record ID to be used to uniquely identify the entity record in Finance and Operations. + +## Primary field + +In Common Data Service, each entity must have a primary field. This field must be a single field of the string type. The primary field is used in Common Data Service in the following scenarios: + +- The default views that are created for an entity include the primary field. +- The quick view form for an entity includes the primary field. +- A lookup to another entity is added to a page and shows the data from the primary field. + +Based on this use of the primary field in Common Data Service, the primary field for a virtual entity for Finance and Operations is designed to use the entity key of the corresponding entity in Finance and Operations. + +Because the primary field in Common Data Service is expected to have only one field of the string type, whereas the entity key in Finance and Operations can have multiple fields of various data types, the entity key fields are converted to strings. The strings are concatenated and separated by a pipe (\|), to a maximum length of 255 characters. Any value that exceeds 255 is truncated. This virtual entity field that represents the primary field is named **mserp\_primaryfield**. + +## Relations + +> [!IMPORTANT] +> A write transaction that spans a virtual entity and a native entity is not supported. We do not recommend using this form of transaction, as there is no way to ensure consistency. + +Relations in Finance and Operations entities are modeled as one-to-many (1:n) or many-to-one (n:1) relations. These relations are modeled as relationships in the virtual entity in Common Data Service. Note that many-to-many (n:n) relations aren't supported in Finance and Operations. + +For example, in Finance and Operations, if Entity A has a foreign key to Entity B, this relation will be modeled as an n:1 relationship in virtual entity Entity A in Common Data Service. The schema name of this relationship in Common Data Service uses the naming convention **mserp\_FK\_\\_\**. This naming convention has a maximum string length of 120 characters. Any relation where the schema name will produce a name that exceeds 120 characters won't be generated in the virtual entity in Common Data Service. + +The external name of this relationship uses the naming convention **FK\_\**. The external name is used to determine the relation in Finance and Operations when the query that is sent to Finance and Operations is built. + +When a relationship is generated for a virtual entity in Common Data Service, a new field of the lookup type is also added to the source entity. In the preceding example, when the relationship is created, a new lookup field that uses the naming convention **mserp\_fk\_\\_id** is added to source entity Entity A. Because there can be several relations in an entity in Finance and Operations, the same number of lookup fields (one per related entity) will be created in the source virtual entity. When this lookup field is added to a page or a view, it will show the primary field value from the related entity. + +A relationship in the virtual entity in Common Data Service will be generated only if the related entity in the relation already exists as a virtual entity in Common Data Service. In the preceding example, if Entity B doesn't exist as a virtual entity in Common Data Service, the relation to Entity B won't be created in Entity A when Entity A is generated as a virtual entity. This relation will be added to Entity A only when Entity B is generated as a virtual entity. Therefore, when a virtual entity is generated for Finance and Operations, validations are done to ensure that only relationships that can be complete and functional are generated in the virtual entity that is being generated. + +In summary, a relationship to another Finance and Operations virtual entity might not exist in the virtual entity for either of the following reasons: + +- The Finance and Operations entity that is participating in the relationship doesn't exist as a virtual entity. +- The length of the name of the relationship exceeds 120 characters. + +Note that if an error is encountered when any part of a Finance and Operations virtual entity is generated in Common Data Service, the virtual entity won't be created at all. If relationships don't exist for either of the preceding reasons, the situation isn't considered an error. + +### Native entity–to–native entity relationships + +Native entity–to–native entity relationships are the standard Common Data Service functionality, where relationships are resolved by using the GUID of the related entity. (This GUID is the entity key.) The GUID identifies the unique entity record in the related entity. + +### Virtual entity–to–virtual entity relationships + +The relationships between two Finance and Operations virtual entities are driven by the relation metadata in the Finance and Operations entities. As was explained earlier, these relations are generated as relationships in Common Data Service when the virtual entity is generated. As in the behavior for native entities in Common Data Service, these relationships use the GUID to identify the unique record of the entity in Finance and Operations. Semantically, the GUID on the Finance and Operations virtual entity behaves like the GUID on the native Common Data Service entity. For information about the implementation of the GUID in Finance and Operations virtual entities, see the [Entity key/primary key](entity-modeling.md#entity-keyprimary-key) section earlier in this topic. + +In the preceding example, the GUID of the related entity is the entity key of Entity B and will be used to build queries to identify a record in Finance and Operation. The relation that Entity A has to Entity B will be used. + +Therefore, in effect, the entity name is the only information that is used in a relation that comes from Finance and Operations. The entity name gives access to the primary field in the related entity, so that it can be shown in the lookup. It also gives access to the GUID of the related entity, so that it can be used in other queries, as was explained earlier. The actual field that the relation is built on in the Finance and Operations entity isn't used at all. + +### Virtual entity–to–native entity relationship + +As was explained earlier, the GUID is the only information that is used to uniquely identify a record in a native Common Data Service entity (including in native entity–to–native entity relationships) or in a Finance and Operations virtual entity (including in virtual entity–to–virtual entity relationships). However, consider an example where you want to show sales orders from Finance and Operations for Account A in Common Data Service. The query that is sent to Finance and Operations for this relationship will have a WHERE clause on the GUID of the entity key of the native accounts entity in Common Data Service, because the sales orders must be filtered for a specific account in Common Data Service. However, because Finance and Operations doesn't have any information about the GUID of the entity in Common Data Service, the query won't return any sales orders. The query will be successful only if the WHERE clause has conditions that are based on the fields that Finance and Operations understands. + +Therefore, how can the GUID of the accounts entity in Common Data Service be replaced with fields that are in Finance and Operations, in such a way that the query that is sent to Finance and Operations will return the correct list of sales orders? + +To solve this issue and enable a rich set of scenarios that allows for virtual entity–to–native entity relationships, relationships can be added to this type of entity. The relation will appear as a relationship when the virtual entity is synced. + +In the above example, the relationship between the SalesOrderHeader virtual entity and the Account native entity should be based on the Account Number and Company fields. By default, the native account entity in Common Data Service does not have a company field. For this example, we will add a company lookup field named new_testcompany to the native Account entity. + +Next, we add a new key named new_accountcompanyidx, which specifies that (accountnumber, new_testcompany) together represent a unique row in the account entity in Common Data Service. + +The next step is to define this relationship in X++. The following example shows sample X++ code. The names of the fields, index, and mapping information should match the names of the fields and indexes created in Common Data Service. In this example, a relationship named “synthaccount” will be created between the virtual SalesorderHeader entity and the native account entity in Common Data Service. The mapped fields make up the new_accountcompanyidx index. The display name for the relationship will be @SYS11307. Note the backslash at the start of the display name. This ensures that the label defines the relationship, so that it is appropriately translated. + +The field mapping indicates which field on the virtual entity maps to the field on the native entity. In the field mapping, the key is the virtual entity field, and the value is the native entity field. + +```x++ +[CDSVirtualEntitySyntheticRelationshipAttribute('synthaccount', 'account', 'accountcompanyidx', '\@SYS11307')] + public static Map syntheticAccountRelationship() + { + Map fieldMapping = new Map(Types::String, Types::String); + + // Assumes the Common Data Service account entity has a key on [msdyn_accountnumber, msdyn_companyid] + // Also assumes that the Common Data Service cdm_Company entity has a key on [msdyn_companycode] + fieldMapping.insert(fieldStr(CDSVirtualEntityTestEntity, StringField), 'msdyn_accountnumber'); + fieldMapping.insert(fieldStr(CDSVirtualEntityTestEntity, DataAreaId), 'msdyn_companyid'); + + return fieldMapping; + } +``` +The next step is to generate or refresh the virtual entity to get the new relationship. Note that relationships between a virtual entity and a native entity cannot be updated in Common Data Service once it is created. The only way to make an update is to physically remove the relationship, refresh the entity, and then physically re-add the relationship in order to resolve the issue. + +This relationship looks like a typical GUID-based relationship, but has extra metadata to translate query filters on the relationship into restrictions on the backing fields. The query that is now generated will have a WHERE clause that is based on the fields that Finance and Operations apps recognize. That query will then return the filtered list of sales orders, as expected. + +### Native entity–to–virtual entity relationships + +Native entity–to–virtual entity relationships works much like native entity–to–native entity relationships. Users associate native records with virtual records in Finance and Operations, and the GUID of the virtual entity is saved on the native entity record. As was explained earlier, the entities that participate in a relationship will have the GUID field of the related entity on them. Therefore, when a quotation in Common Data Service is associated with a customer in a Finance and Operations virtual entity, the GUID of the customer virtual entity will be saved in the quotation entity. This behavior enables records to be retrieved as expected, by using standard Common Data Service functionality. + +## Enums + +Enums in Finance and Operations are modeled as OptionSets in Common Data Service. When a virtual entity for Finance and Operations is generated, the required enums are generated as OptionSets. If an OptionSet already exists, it's used instead. + +## Company + +An entity in Finance and Operations can be bound to a company, or it can be global. The virtual entity for a Finance and Operations entity that is bound to a company will have a relationship to the cdm\_company entity in Common Data Service. The cdm\_company entity is a native entity in Common Data Service and is part of the Dynamics365Company solution. As always, when a relationship is created, a lookup field is also created in the virtual entity for the related entity (cdm\_company in this case). This lookup field is named **Company**, and it must be used to provide an optimal user experience where users can select a value in a list or go to the details of the related record. A field that is named **Company Code** is also added in the virtual entity. The value is a four-character string. This field must be used in programming. + +## Attachments + +Attachments in Finance and Operations entities are supported on a per-entity basis. For example, an invoice header entity will implement an invoice-related attachments entity to [enable attachments via entities](../../fin-ops/organization-administration/configure-document-management.md#how-can-attachments-be-extracted-from-the-system). + +Entities of this type will have relations with the corresponding attachments entity in Finance and Operations. Therefore, they will follow the same pattern as the other relations that were discussed earlier. In other words, Finance and Operations entities that have implemented attachments functionality will also make attachments available by using virtual entities. Finance and Operations entities that don't support attachments also won't support attachments when they are virtualized in Common Data Service. + +Note that Finance and Operations virtual entities support only the reading of attachments. They don't currently support the creation, update, or deletion of attachments by using virtual entities. + +## OData actions + +OData actions in the Finance and Operations entities are made available as custom actions in Common Data Service. For more information about custom actions and what they enable in Common Data Service, see [Custom actions](https://docs.microsoft.com/powerapps/developer/common-data-service/custom-actions). + +Input and output parameters of the following types are supported. If an input or output parameter is of a different type, the OData action doesn't appear as the SDK message in Common Data Service. + +- Integer +- String +- Guid +- Boolean +- Date/Datetime + +Here are some examples of OData actions that are supported in Finance and Operations entities, but that aren't supported in the corresponding virtual entities in Common Data Service: + +- RetailStoreTenderTypeTable.queryDistinctTenderTypeIdAndName (a collection of RetailStoreTenderTypeTable entity) +- DocumentRoutingClientApp.syncPrinters (DocumentRoutingClientApp entity) +- DocumentRoutingClientApp.updateJobStatus (DocumentRoutingJobStatus enum) +- DimensionCombination.getCombinationDisplayValue (LedgerJournalACType enum) + +## Labels and localization + +Labels that are defined on metadata, such as entity names and field names in Finance and Operations, are retrieved when virtual entities are generated in Common Data Service. The labels are retrieved by passing the list of language locales that are installed in Common Data Service. Finance and Operations returns each label as a list of locale/value sets that are then used to construct a label instance in Common Data Service. Only the language packs that exist at the time of entity generation or update are included. Additionally, only labels that Finance and Operations has provided a translation for are included. Any missing translations revert to the label ID, such as **\@SYS:DataEntity**. After a new language pack is installed in Common Data Service, existing entities must be updated to pick up the new label information, if labels in that language exist in Finance and Operations. + +Any runtime labels are returned in the language of the current user context. In other words, they are returned in the language that is specified on that user's UserInfo record in Finance and Operations. This behavior also applies to error messages. + +## Error handling + +Finance and Operations create, read, update, and delete (CRUD) business logic on entities and backing tables is run when it's called through the virtual entity in Common Data Service. If any exception is thrown on the Finance and Operations side, the last message in the error log is returned to Common Data Service and is thrown as an InvalidPluginExecutionException exception that contains the message from Finance and Operations. Because the Finance and Operations code runs in the context of the user, the language of the error message is based on the language that is specified on the UserInfo record in Finance and Operations. If any messages that are written to the info log in Finance and Operations don't result in an exception, they aren't shown in Common Data Service. + +## Calculated/unmapped fields + +Calculated and unmapped fields in Finance and Operations entities are also available in the corresponding virtual entities in Common Data Service. diff --git a/dev-itpro/powerplatform/faq.md b/dev-itpro/powerplatform/faq.md new file mode 100644 index 0000000000..ebb762aefd --- /dev/null +++ b/dev-itpro/powerplatform/faq.md @@ -0,0 +1,110 @@ +--- +# required metadata + +title: Finance and Operations virtual entities FAQ +description: This topic is a list of frequently asked questions about Finance and Operations virtual entities. +author: Sunil-Garg +manager: AnnBe +ms.date: 07/13/2020 +ms.topic: article +ms.prod: +ms.service: dynamics-ax-applications +ms.technology: + +# optional metadata + +# ms.search.form: +audience: Developer, IT Pro +# ms.devlang: +ms.reviewer: sericks +ms.search.scope: Operations +# ms.tgt_pltfrm: +# ms.custom: NotInToc +ms.search.region: Global +# ms.search.industry: +ms.author: sunilg +ms.search.validFrom: 2020-05-31 +ms.dyn365.ops.version: 10.0.12 +--- + +# Finance and Operations virtual entities FAQ + +[!include[banner](../includes/banner.md)] + +> [!IMPORTANT] +> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). + +This topic is a collection of frequently asked questions about Finance and Operations virtual entities. + +### Do Tier 1 Finance and Operations environments or demo topologies work? + +Yes, Tier 1 and DEVTEST and DEMO topologies should work. + +### What version of Finance and Operations do I need? + +10.0.12 is the minimum version that is required. + +### Can a solution from an independent software vendor (ISV) take a dependency on virtual entities? What does the application lifecycle management (ALM) look like? + +Yes. The virtual entities are all generated in the MicrosoftOperationsERPVE solution, which isAPI-managed In other words, the items in the solution change as you make entities visible or hidden, but the solution is still a managed solution that you can take dependency on. The standard ALM flow just takes a standard reference to a virtual entity from this solution with the **Add existing** option in the ISV solution. Missing dependency of the solution will be checked when the solution is imported and during import, if a specified virtual entity doesn't yet exist, the virtual entity is automatically made visible. + +### Which entities from Finance and Operations do users see in the catalog in Common Data Service? + +Generally, users see all entities where **IsPublic** is set to **Yes**. These entities are the same entities that are currently visible in Open Data Protocol (OData). + +### Do all Microsoft Power Platform users have to be users in Finance and Operations? + +Any user of Microsoft Power Platform who tries to access Finance and Operations data through a virtual entity must also exist as a user in Finance and Operations. Therefore, technically, not *all* users have to be users in Finance and Operations. Only those users who access Finance and Operations data through virtual entities must be users in Finance and Operations. + +### Where do I find the catalog entity? + +In the **Advanced find** window, the entity is named **Available Finance and Operations Entities**. + +### Is there a way to specify a company when I perform data operations on a virtual entity? + +Yes. Although the company is implicit in Finance and Operations, it's an explicit field on each company-striped entity in Common Data Service. You can use either the **Company Code** field, where the value is a four-character string, or the **Company** field, which is a lookup to cdm\_Company. Both approaches provide the same information. + +### Can I change the prefix for the virtual entities? + +No. All Finance and Operations virtual entities should be generated in the MicrosoftOperationsERPVE solution, and they should all have the "mserp\_" prefix. This prefix should not be changed. If you have a scenario where you believe the prefix has to be changed, you should share that scenario with Microsoft. + +### How can I filter data in an app that is created by using Power Apps, based on the current user or any other dynamic criteria, such as today-10? + +You can write a pre-operation plug-in on the RetrieveMultiple message of the entity and change the criteria on the query in it. Alternatively, you can write a post-operation plug-in to filter the results before they are returned. + +### Can I pin a model-driven app into Finance and Operations? + +No, it isn't currently possible to pin a model-driven app into Finance and Operations. + +### How can I show, in the same grid, data from multiple virtual entities that are joined to a physical entity record in Common Data Service? + +This approach isn't currently possible in Common Data Service. + +### How do I add subcomponents in the new Power Apps experience? + +As in the previous Power Apps user interface (UI), you must redo the **Add Existing** operation. After the solution is selected, and Customer Groups has already been added as an entity, follow these steps. + +1. Select **Add existing** \> **Entity**. +2. Select customer group entity, and then select **Next**. +3. Under **Components**, select **Select components**. +4. Select the fields, relationships, and forms that you want, and then select **Add**. + +### If I want a default value to be entered in a field during pre-create, will an initValue on the data entity work? + +Yes. Here is the order of calls: + +1. Common Data Service sends a create or update message. +2. All the existing logic on the Finance and Operations entity and backing tables is invoked. This logic includes default value entry that might change values. +3. Common Data Service sends another Retrieve (single) message to get the latest copy of the data, including any fields that default values were entered for. + +### Can I debug Finance and Operations when we do a create, read, update, and delete (CRUD) operation from Common Data Service? If so, which process do I have to attach? + +Yes, to debug in Finance and Operations, open Visual Studio as an admin. Typically, Finance and Operations apps run under w3wp.exe as a process. However, when you open Visual Studio as an admin, IISExpress.exe is automatically opened, and Finance and Operations is hosted there. You can attach to IISExpress.exe (or to w3wp.exe if not running Visual Studio as an admin). To set breakpoints in the virtual entity code, find the **CDSVirtualEntityAdapter** and **CDSVirtualEntityController** classes. The adapter class is the first class that is called, and it only does serialization/deserialization. It then delegates to the controller class to do the actual queries. Therefore, the controller class is usually the easiest place to put breakpoints. + +### Does the form business logic in Finance and Operations get called through virtual entities? + +Finance and Operations business logic that resides on forms isn't invoked through virtual entities. Instead, you should expect the same behavior that you get through OData access to the same entities. The expectation is that an entity that is exposed to OData (that is, **IsPublic** is set to **Yes**) has appropriate protections to ensure that data can't be corrupted. If any entity lacks this protection, that situation represents a bug in the entity. If you see differences in entity behavior between OData and virtual entities, that situation represents a bug in the virtual entity feature. + +### If I develop a new Finance and Operations entity and want to see it in Common Data Service, do I have to select Refresh entity list in Finance and Operations? Do I have to do anything in Common Data Service? + +In theory, no, you don't have to refresh the entity list. At most, you might have to either reset Internet Information Services (IIS) or restart IIS Express, depending on where Application Object Server (AOS) is running. The fact that the list of entities is accurate is cached in SysGlobalObjectCache, which is a per-process cache. Any time that this cache doesn't indicate that the list is accurate, the list is rebuilt. The rebuild process takes about five seconds. Therefore, when you restart your AOS process (w3wp.exe or iisexpress.exe), the list will be accurate the next time that you query it from Common Data Service. Additionally, although recompilation *should* flush the SysGlobalObjectCache cache, it might not. In that case, an AOS restart will flush it. diff --git a/dev-itpro/powerplatform/overview.md b/dev-itpro/powerplatform/overview.md new file mode 100644 index 0000000000..d161453915 --- /dev/null +++ b/dev-itpro/powerplatform/overview.md @@ -0,0 +1,64 @@ +--- +# required metadata + +title: Microsoft Power Platform integration with Finance and Operations +description: This topic describes virtual entities for Finance and Operations in Common Data Service. +author: Sunil-Garg +manager: AnnBe +ms.date: 07/13/2020 +ms.topic: article +ms.prod: +ms.service: dynamics-ax-applications +ms.technology: + +# optional metadata + +# ms.search.form: +audience: Developer, IT Pro +# ms.devlang: +ms.reviewer: sericks +ms.search.scope: Operations +# ms.tgt_pltfrm: +# ms.custom: NotInToc +ms.search.region: Global +# ms.search.industry: +ms.author: sunilg +ms.search.validFrom: 2020-10-31 +ms.dyn365.ops.version: 10.0.0 +--- + +# Microsoft Power Platform integration with Finance and Operations + +[!include[banner](../includes/banner.md)] + +> [!IMPORTANT] +> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). + +Finance and Operations is a virtual data source in Common Data Service, and enables full create, read, update, delete (CRUD) operations from Common Data Service and Microsoft Power Platform. By definition, the data for virtual entities doesn't reside in Common Data Service. Instead, it continues to reside in the application where it belongs. To enable CRUD operations on Finance and Operations entities from Common Data Service, entities must be made available as virtual entities in Common Data Service. The allows CRUD operations to be performed, from Common Data Service and Microsoft Power Platform, on data that resides in Finance and Operations apps. + +## Prerequisite reading + +To understand the architecture of virtual entities for Finance and Operations apps, you must understand how Common Data Service and virtual entities work. Therefore, the following documentation is a prerequisite: + +- [What is Common Data Service?](https://docs.microsoft.com/powerapps/maker/common-data-service/data-platform-intro) +- [Entity overview](https://docs.microsoft.com/powerapps/maker/common-data-service/entity-overview) +- [Entity relationships overview](https://docs.microsoft.com/powerapps/maker/common-data-service/relationships-overview) +- [Create and edit virtual entities that contain data from an external data source](https://docs.microsoft.com/powerapps/maker/common-data-service/create-edit-virtual-entities) +- [What is Power Apps portals?](https://docs.microsoft.com/powerapps/maker/portals/overview) +- [Overview of creating apps in Power Apps](https://docs.microsoft.com/powerapps/maker/) + +## Virtual entities for Finance and Operations apps + +All Open Data Protocol (OData) entities in Finance and Operations are available as virtual entities in Common Data Service, and therefore also in Power Platform. Makers can now build experiences in customer engagement apps with data directly from Finance and Operations with full CRUD capability and without copying to Common Data Service. Power Apps Portals can be used to build external-facing websites that enable collaboration scenarios for business processes in Finance and Operations. + +## Architecture + +Virtual entities are a Common Data Service concept that is useful beyond Finance and Operations. The following illustration shows how the Finance and Operations provider for virtual entities is implemented. Six primary methods are implemented by the provider. The first five methods are the standard CRUD operations: **Create**, **Update**, **Delete**, **Retrieve**, and **RetrieveMultiple**. The last method, **PerformAction**, is used to call OData actions, as described later in this topic. Calls to the Finance and Operations Virtual Entity Data Provider (shown as "VE Plugin" in the illustration) will cause a Secure Sockets Layer (SSL)/Transport Layer Security (TLS) 1.2 secure web call to the CDSVirtualEntityService web API endpoint of Finance and Operations. This web service then converts the queries into calls to the associated physical entities in Finance and Operations, and invokes CRUD or OData operations on those entities. Because a Finance and Operations entity is directly invoked in all operations, any business logic on the entity or its backing tables is also invoked. + +[![Architecture of virtual entities for Finance and Operations apps](../media/fovearchitecture.png)](../media/fovearchitecture.png) + +During calls, there are two points of translation from Common Data Service to Finance and Operations apps. The first point of translation occurs in the VE Plugin, which translates concepts such as entity physical names into Finance and Operations entity names. It also converts some well-known concepts, such as Company references. The web service call still uses the EntityCollection, Entity, and QueryExpression objects to express the operations that are performed, by using the translated entity names and concepts from the VE Plugin. Finally, the CDSVirtualEntityAdapterService web API in Finance and Operations completes the translation from QueryExpression to QueryBuildDataSource and other internal Finance and Operations language constructs. + +All calls between Common Data Service and Finance and Operations as part of virtual entities are done as service-to-service (S2S) calls by using the Azure Active Directory (Azure AD) application that is specified in the configuration. The user of this application should have access *only* to the CDSVirtualEntityAdapterService web API and the Catalog entity, CDSVirtualEntityListEntity. These privileges are included in the out-of-box security role that is named CDSVirtualEntityApplication. During the S2S calls, Common Data Service provides the identity of the user in Common Data Service who is invoking the action. The CDSVirtualEntityAdapterService web API looks up the associated user in Finance and Operations and runs the query in the context of that user. Therefore, the S2S call doesn't have to have explicit access to all the Finance and Operations entities. Instead, it can rely on the privileges of the user who is invoking the action to determine data access. + +Power Apps Portal can also access virtual entities. Because Power Apps Portal authorization is based on contact records, a mapping between contact records and Finance and Operations users is maintained in the msdyn\_externalportalusermapping table in Common Data Service. This table should be editable only by highly privileged users in Common Data Service, who have the rights to control the security access of portal users to Finance and Operations virtual entities. Any Finance and Operations user who is set up for Power Apps Portal access must have the CDSVirtualEntityAuthorizedPortalUser security role assigned, and can't have the System administrator or Security administrator role assigned. Regardless of the Power Apps Portal security setting that is applied to virtual entities, the resulting query to Finance and Operations apps is always run as the associated Finance and Operations user, and is subject to that user's entity and row security settings. Anonymous portal access is also supported. For information about this type of access and how it can be done, see [Power Apps Portal reference](power-portal-reference.md). diff --git a/dev-itpro/powerplatform/power-portal-reference.md b/dev-itpro/powerplatform/power-portal-reference.md new file mode 100644 index 0000000000..f56fe8aa84 --- /dev/null +++ b/dev-itpro/powerplatform/power-portal-reference.md @@ -0,0 +1,53 @@ +--- +# required metadata + +title: Power Apps portals with Finance and Operations +description: This topic explains how Power Apps portals can be used with Finance and Operations. +author: Sunil-Garg +manager: AnnBe +ms.date: 07/13/2020 +ms.topic: article +ms.prod: +ms.service: dynamics-ax-applications +ms.technology: + +# optional metadata + +# ms.search.form: +audience: Developer, IT Pro +# ms.devlang: +ms.reviewer: sericks +ms.search.scope: Operations +# ms.tgt_pltfrm: +# ms.custom: NotInToc +ms.search.region: Global +# ms.search.industry: +ms.author: sunilg +ms.search.validFrom: 2020-05-31 +ms.dyn365.ops.version: 10.0.12 +--- + +# Power Apps portals with Finance and Operations + +[!include[banner](../includes/banner.md)] + +> [!IMPORTANT] +> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). + +Power Apps portals will enable create, update, and delete (CRUD) operations to Finance and Operations entities that are available as virtual entities in Common Data Service. This topic explains the scenarios that are implemented in Power Apps portals for Finance and Operations apps. + +## Anonymous access from Power Apps portals + +Collaboration scenarios in business processes such as bidding or onboarding of prospects in Finance and Operations require that external users participate from the Power Apps portal, even though they aren't users in Finance and Operations apps. The simplicity of anonymous access is appealing in these types of scenarios because the users, who might not be Finance and Operations apps users, don't have to sign in. However, they are expected to perform CRUD operations in Finance and Operations to complete any meaningful tasks in the business processes. + +To ensure that only the required entities are enabled for anonymous access, a user in Finance and Operations must be designated as the user who is used for anonymous access. This designation is configured in the **Anonymous portal access user ID** field on the **Virtual entity** tab on the **System parameters** page (**System administration \> System parameters**). The designated user can then be assigned to duties and security roles to control access to specific data that must be made available to all users who will interact anonymously from the Power Portal. + +Note that because this scenario involves anonymous access, the only user context that matters, from a security perspective, is the user who is designated in the **Anonymous portal access user ID** field. + +## Authenticated access from Power Apps portals + +Fully authenticated user access from Power Apps portals to Finance and Operations lets users in Finance and Operations also interact from Power Apps portals. A user who signs in to the Power Apps portal is also a known user in Finance and Operations who has appropriate security roles based on job requirements. These roles govern the security access to data for the authenticated user in Power Portal. In addition, any Finance and Operations user that is expected to also use Power Apps portal to access Finance and Operations data must also belong to the **CDSVirtualEntityAuthenticatedPortalUser** security role. This provides an additional layer of security and also provides a way to know the total users that are authorized to access from Power Apps portals. + +Because Power Apps portals authentication is linked to the Contacts entity in Common Data Service, a mapping must be established between the Common Data Service contact and the corresponding user in Finance and Operations. This mapping can be done by adding entries to the **msdyn\_externalportalusermapping** entity. From a security perspective, the scope of virtual entities that are made available to authenticated users must be configured as **Global** in the Power Apps portal. + +When authenticated users from a different tenant need to be added to Finance and Operations as users, you must use the [Create new user](../sysadmin/tasks/create-new-users.md) process in Finance and Operations. This process adds cross-tenant users as Microsoft Azure Active Directory (Azure AD) business-to-business (B2B) guest users. From b627c1144a1aeb2c830f51cafc674c6ce913acda Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 12:00:49 +0200 Subject: [PATCH 115/950] Create devenv-application-insights-for-extensions.md --- ...env-application-insights-for-extensions.md | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 dev-itpro/developer/devenv-application-insights-for-extensions.md diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md new file mode 100644 index 0000000000..e17a740ec8 --- /dev/null +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -0,0 +1,40 @@ +--- +title: Using Key Vault Secrets in Business Central Extensions +description: Describes how to use an Azure Key vault with Business Central extensions. +ms.custom: na +ms.date: 04/01/2020 +ms.reviewer: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +author: jswymer +--- + +# Sending Extension Telemetry to Azure Application Insights + +This article describes how to develop an extension to emit telemetry to an Application Insights resource in Azure. There are several operations + +#### Using Application Insights + + + +1. Create an Application Insights resource in Azure if you don't have one. + + The Application Insights resource will be assigned an instrumentation key. Copy this key because you'll need it to enable Application Insights in the [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)]. + + For more information, see [Create an Application Insights resource](/azure/azure-monitor/app/create-new-resource). + +2. In the app.json file of the extension, add the `"applicationInsightsKey"`: + + ``` + "applicationInsightsKey": [""] + ``` +3. Now, you can run your extensions and view data in Application Insights. + + For more information, see [Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) and [Analyzing App Key Vault Secret Trace Telemetry](../administration/telemetry-extension-key-vault-trace.md). + +## See Also +[Getting Started with AL](devenv-get-started.md) +[Publishing and Installing Extensions](devenv-how-publish-and-install-an-extension-v2.md) +[Configuring Business Central Server](../administration/configure-server-instance.md) \ No newline at end of file From d721c0ca3e949ceecf3e82fc3d82bb2c7d16670b Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 12:36:37 +0200 Subject: [PATCH 116/950] updates --- .../administration/telemetry-overview.md | 3 +- ...env-application-insights-for-extensions.md | 39 ++++++++++++------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 684855186e..d930c67e1a 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -50,7 +50,8 @@ Sending telemetry data to Application Insights requires you have an Application - For [!INCLUDE[prodshort](../developer/includes/prodshort.md)] On-premises, see [Enable Sending Telemetry to Application Insights](telemetry-enable-application-insights.md). -- For extensions, see [] +- For extensions, see [Sending Extension Telemetry to Azure Application Insights](../developer/devenv-application-insights-for-extensions.md). + ## Viewing telemetry data in Application Insights Telemetry from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is stored in Azure Monitor Logs in the *traces* table. You can view collected data by writing log queries. Log queries are written in the Kusto query language (KQL). For more information, see [Logs in Azure Monitor](/azure/azure-monitor/platform/data-platform-logs) and [Overview of log queries in Azure Monitor](/azure/azure-monitor/log-query/log-query-overview). diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md index e17a740ec8..67f10f8a9e 100644 --- a/dev-itpro/developer/devenv-application-insights-for-extensions.md +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -1,8 +1,8 @@ --- -title: Using Key Vault Secrets in Business Central Extensions -description: Describes how to use an Azure Key vault with Business Central extensions. +title: Sending Extension Telemetry to Azure Application Insights +description: Describes how to configure an extension to send telemetry data to Azure Application Insights. ms.custom: na -ms.date: 04/01/2020 +ms.date: 12/08/2020 ms.reviewer: na ms.suite: na ms.tgt_pltfrm: na @@ -13,28 +13,37 @@ author: jswymer # Sending Extension Telemetry to Azure Application Insights -This article describes how to develop an extension to emit telemetry to an Application Insights resource in Azure. There are several operations +[!INCLUDE[2020_releasewave2.md](../includes/2020_releasewave2.md)] -#### Using Application Insights +This article describes how to develop an extension to send telemetry data to an Application Insights resource in Azure. [!INCLUDE[prodshort](includes/prodshort.md)] emits telemetry data for several operations that occur when extension code is run. You can configure an extension to send this telemetry data to an Application Insights resource on Microsoft Azure. For an overview about the telemetry with Application Insights, see [Monitoring and Analyzing Telemetry](../administration/telemetry-overview.md). +This feature targets publishers of per-tenant extensions to get insight into issues in their extension before partners and customers report them. +> [!NOTE] +> This feature is not supported for AppSource extensions. AppSource extensions are automatically set up to send telemetry to Application Insights. -1. Create an Application Insights resource in Azure if you don't have one. - The Application Insights resource will be assigned an instrumentation key. Copy this key because you'll need it to enable Application Insights in the [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)]. +## Get an Application Insights resource in Azure - For more information, see [Create an Application Insights resource](/azure/azure-monitor/app/create-new-resource). +The first thing to do is to create an Application Insights resource in Azure if you don't have one. For more information, see [Create an Application Insights resource](/azure/azure-monitor/app/create-new-resource). -2. In the app.json file of the extension, add the `"applicationInsightsKey"`: +The Application Insights resource is assigned an instrumentation key. Copy this key because you'll need it to enable Application Insights in the [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)] - ``` - "applicationInsightsKey": [""] - ``` -3. Now, you can run your extensions and view data in Application Insights. - For more information, see [Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) and [Analyzing App Key Vault Secret Trace Telemetry](../administration/telemetry-extension-key-vault-trace.md). +## Add the Application Insights Key to the extension's app.json + +The next step is to add `"applicationInsightsKey"`setting the extension's app.json as shown: + +``` +"applicationInsightsKey": [""] +``` + +Replace `` with your key. + +When done, build the extension package, then publish and install it as usual. When the extension is run from [!INCLUDE[prodshort](includes/prodshort.md)], Application Insights gathers the telemetry data for viewing. ## See Also [Getting Started with AL](devenv-get-started.md) [Publishing and Installing Extensions](devenv-how-publish-and-install-an-extension-v2.md) -[Configuring Business Central Server](../administration/configure-server-instance.md) \ No newline at end of file +[JSON Files](devenv-json-files.md) +[Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) \ No newline at end of file From c039c7450b7454dea3f5d24a52a770eda727b3c9 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 12:42:53 +0200 Subject: [PATCH 117/950] Update telemetry-overview.md --- dev-itpro/administration/telemetry-overview.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index d930c67e1a..034d8cf0f1 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -18,13 +18,11 @@ ms.author: jswymer [!INCLUDE[prodshort](../developer/includes/prodshort.md)] emits telemetry data for various activities and operations on tenants and extensions. Whether running [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Online or On-premises, you can set up your tenants to send telemetry to Application Insights. Application Insights is a service hosted within Azure that gathers telemetry data for analysis and presentation. For more information, see [What is Application Insights?](/azure/azure-monitor/app/app-insights-overview). Monitoring telemetry gives you a look at the activities and general health of your tenants. It helps you diagnose problems and analyze operations that affect performance. - ## Service-level and extension-level telemetry -Application Insights can be enabled on two different levels: service and extension. When enabled on the service, either for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online tenant or on-premises [!INCLUDE[server](../developer/includes/server.md)] instance, telemetry is emitted to a single Application Insights resource for gathering data tenant-wide operations. - -It can also be enabled a per-extension basis. An Application Insights key is set in the extension's manifest (app.json file). At runtime, certain events related to the extension are emitted to the Application Insights resource. This feature targets publishers of per-tenant extensions to get insight into issues in their extension before partners and customers report them. +Application Insights can be enabled on two different levels: service and extension. When enabled on the service, either for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online tenant or on-premises [!INCLUDE[server](../developer/includes/server.md)] instance, telemetry is emitted to a single Application Insights resource for gathering data on tenant-wide operations. +With [!INCLUDE[prodshort](../developer/includes/prodshort.md)] 2020 release wave 2 and later, Application Insights can also be enabled a per-extension basis. An Application Insights key is set in the extension's manifest (app.json file). At runtime, certain events related to the extension are emitted to the Application Insights resource. This feature targets publishers of per-tenant extensions to get insight into issues in their extension before partners and customers report them. ## Available telemetry From 481094c59e5c66cfb1e6f7fb7074e1eeff1cfab3 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 12:44:17 +0200 Subject: [PATCH 118/950] Update telemetry-overview.md --- dev-itpro/administration/telemetry-overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 034d8cf0f1..0e336a3972 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -18,9 +18,9 @@ ms.author: jswymer [!INCLUDE[prodshort](../developer/includes/prodshort.md)] emits telemetry data for various activities and operations on tenants and extensions. Whether running [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Online or On-premises, you can set up your tenants to send telemetry to Application Insights. Application Insights is a service hosted within Azure that gathers telemetry data for analysis and presentation. For more information, see [What is Application Insights?](/azure/azure-monitor/app/app-insights-overview). Monitoring telemetry gives you a look at the activities and general health of your tenants. It helps you diagnose problems and analyze operations that affect performance. -## Service-level and extension-level telemetry +## Tenant-level and extension-level telemetry -Application Insights can be enabled on two different levels: service and extension. When enabled on the service, either for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online tenant or on-premises [!INCLUDE[server](../developer/includes/server.md)] instance, telemetry is emitted to a single Application Insights resource for gathering data on tenant-wide operations. +Application Insights can be enabled on two different levels: tenant and extension. When enabled on the tenant, either for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online tenant or on-premises [!INCLUDE[server](../developer/includes/server.md)] instance, telemetry is emitted to a single Application Insights resource for gathering data on tenant-wide operations. With [!INCLUDE[prodshort](../developer/includes/prodshort.md)] 2020 release wave 2 and later, Application Insights can also be enabled a per-extension basis. An Application Insights key is set in the extension's manifest (app.json file). At runtime, certain events related to the extension are emitted to the Application Insights resource. This feature targets publishers of per-tenant extensions to get insight into issues in their extension before partners and customers report them. From 2262879af6d933775de55b32e476b4f6ee6f6196 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 12:51:23 +0200 Subject: [PATCH 119/950] updates --- dev-itpro/administration/telemetry-overview.md | 2 +- .../developer/devenv-application-insights-for-extensions.md | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 0e336a3972..854094cb14 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -22,7 +22,7 @@ ms.author: jswymer Application Insights can be enabled on two different levels: tenant and extension. When enabled on the tenant, either for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online tenant or on-premises [!INCLUDE[server](../developer/includes/server.md)] instance, telemetry is emitted to a single Application Insights resource for gathering data on tenant-wide operations. -With [!INCLUDE[prodshort](../developer/includes/prodshort.md)] 2020 release wave 2 and later, Application Insights can also be enabled a per-extension basis. An Application Insights key is set in the extension's manifest (app.json file). At runtime, certain events related to the extension are emitted to the Application Insights resource. This feature targets publishers of per-tenant extensions to get insight into issues in their extension before partners and customers report them. +With [!INCLUDE[prodshort](../developer/includes/prodshort.md)] 2020 release wave 2 and later, Application Insights can also be enabled on a per-extension basis. An Application Insights key is set in the extension's manifest (app.json file). At runtime, certain events related to the extension are emitted to the Application Insights resource. This feature targets publishers of per-tenant extensions to give them insight into issues in their extension before partners and customers report them. ## Available telemetry diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md index 67f10f8a9e..e773136df6 100644 --- a/dev-itpro/developer/devenv-application-insights-for-extensions.md +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -15,12 +15,10 @@ author: jswymer [!INCLUDE[2020_releasewave2.md](../includes/2020_releasewave2.md)] -This article describes how to develop an extension to send telemetry data to an Application Insights resource in Azure. [!INCLUDE[prodshort](includes/prodshort.md)] emits telemetry data for several operations that occur when extension code is run. You can configure an extension to send this telemetry data to an Application Insights resource on Microsoft Azure. For an overview about the telemetry with Application Insights, see [Monitoring and Analyzing Telemetry](../administration/telemetry-overview.md). - -This feature targets publishers of per-tenant extensions to get insight into issues in their extension before partners and customers report them. +This article describes how to develop an extension to send telemetry data to an Azure Application Insights for monitoring and analyzing. [!INCLUDE[prodshort](includes/prodshort.md)] emits telemetry data for several operations that occur when extension code is run. You can configure an extension to send this telemetry data to a specific Application Insights resource on Microsoft Azure. For an overview about the telemetry with Application Insights, see [Monitoring and Analyzing Telemetry](../administration/telemetry-overview.md). > [!NOTE] -> This feature is not supported for AppSource extensions. AppSource extensions are automatically set up to send telemetry to Application Insights. +> This feature targets publishers of per-tenant extensions to give them insight into issues in their extension before partners and customers report them. This feature is not supported for AppSource extensions, because these extensions are automatically set up to send telemetry to Application Insights. ## Get an Application Insights resource in Azure From c40a57c4d9eebe44ab4768ea1ac063eaa1fedbef Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Wed, 12 Aug 2020 12:54:19 +0200 Subject: [PATCH 120/950] draft --- dev-itpro/powerplatform/admin-reference.md | 71 ++++------- .../application-lifecycle-management.md | 69 ++++------ dev-itpro/powerplatform/entity-modeling.md | 119 ++++++++---------- dev-itpro/powerplatform/faq.md | 71 ++++------- dev-itpro/powerplatform/overview.md | 55 +++----- .../powerplatform/power-portal-reference.md | 49 +++----- 6 files changed, 166 insertions(+), 268 deletions(-) diff --git a/dev-itpro/powerplatform/admin-reference.md b/dev-itpro/powerplatform/admin-reference.md index 8f4435c202..114e7f4d81 100644 --- a/dev-itpro/powerplatform/admin-reference.md +++ b/dev-itpro/powerplatform/admin-reference.md @@ -1,59 +1,42 @@ --- -# required metadata - -title: Finance and Operations and Common Data Service admin reference -description: This topic covers set up and configuration of virtual entities for Finance and Operations. -author: Sunil-Garg -manager: AnnBe -ms.date: 07/13/2020 +title: "Business Central and Common Data Service admin reference" +ms.custom: na +ms.date: 08/12/2020 +ms.reviewer: solsen +ms.suite: na +ms.tgt_pltfrm: na ms.topic: article -ms.prod: -ms.service: dynamics-ax-applications -ms.technology: - -# optional metadata - -# ms.search.form: -audience: Developer, IT Pro -# ms.devlang: -ms.reviewer: sericks -ms.search.scope: Operations -# ms.tgt_pltfrm: -# ms.custom: NotInToc -ms.search.region: Global -# ms.search.industry: -ms.author: sunilg -ms.search.validFrom: 2020-05-31 -ms.dyn365.ops.version: 10.0.12 +ms.service: "dynamics365-business-central" +author: solsen --- -# Finance and Operations and Common Data Service admin reference +# Business Central and Common Data Service admin reference [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires [Platform updates for version 10.0.12 of Finance and Operations apps](../get-started/whats-new-platform-update-10-0-12.md) and service update 189 for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires [Platform updates for version 10.0.12 of Business Central apps](../get-started/whats-new-platform-update-10-0-12.md) and service update 189 for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -This topic provides step-by-step instructions about how to set up and configure virtual entities for Finance and Operations apps in Common Data Service. +This topic provides step-by-step instructions about how to set up and configure virtual entities for Business Central apps in Common Data Service. ## Getting the solution -The Common Data Service solution for Finance and Operations virtual entities must be installed from Microsoft AppSource virtual entity solution. For more information, see [Finance and Operations virtual entity](https://appsource.microsoft.com/product/dynamics-crm/mscrm.finance_and_operations_virtual_entity). +The Common Data Service solution for Business Central virtual entities must be installed from Microsoft AppSource virtual entity solution. For more information, see [Business Central virtual entity](https://appsource.microsoft.com/product/dynamics-crm/mscrm.finance_and_operations_virtual_entity). Ensure the following solutions are installed in Common Data Service. These solutions must be extracted from the downloaded package. -- **Dynamics365Company** - This adds the **Company** entity, which is referenced by all Finance and Operations entities with a PrimaryCompanyContext metadata value. +- **Dynamics365Company** - This adds the **Company** entity, which is referenced by all Business Central entities with a PrimaryCompanyContext metadata value. -- **MicrosoftOperationsVESupport** - This provides the core support for the Finance and Operations virtual entity feature. +- **MicrosoftOperationsVESupport** - This provides the core support for the Business Central virtual entity feature. -- **MicrosoftOperationsERPCatalog** - This provides a list of available Finance and Operations entities through the mserp_financeandoperationsentity virtual entity. +- **MicrosoftOperationsERPCatalog** - This provides a list of available Business Central entities through the mserp_financeandoperationsentity virtual entity. - **MicrosoftOperationsERPVE** - This is the API-managed solution, which will contain the generated virtual entities as they are made visible. ## Authentication and authorization -After the solutions are imported in the Common Data Service environment, both environments must be set up to connect to each other. Common Data Service will call Finance and Operations using Service-to-Service (S2S) authentication, based on an Azure Active Directory (AAD) application. This new AAD application represents the single instance of the Common Data Service environment. If you have multiple pairs of Common Data Service and Finance and Operations environments, separate AAD applications for each pair must be created to ensure connections are established between the correct pair of Finance and Operations and Common Data Service environments. The following procedure shows the creation of the AAD application. +After the solutions are imported in the Common Data Service environment, both environments must be set up to connect to each other. Common Data Service will call Business Central using Service-to-Service (S2S) authentication, based on an Azure Active Directory (AAD) application. This new AAD application represents the single instance of the Common Data Service environment. If you have multiple pairs of Common Data Service and Business Central environments, separate AAD applications for each pair must be created to ensure connections are established between the correct pair of Business Central and Common Data Service environments. The following procedure shows the creation of the AAD application. > [!IMPORTANT] -> The AAD application must be created on the same tenant as Finance and Operations. +> The AAD application must be created on the same tenant as Business Central. 1. Go to **\> Azure Active Directory \> App registrations**. @@ -79,11 +62,11 @@ After the solutions are imported in the Common Data Service environment, both en - Select **Save**. A key will be created and displayed. Copy this value for later use. -The AAD application created above will be used by Common Data Service to call Finance and Operations apps. As such, it must be trusted by Finance and Operations and associated with a user account with the appropriate rights in Finance and Operations. A special service user must be created in Finance and Operations with rights *only* to the virtual entity functionality, and no other rights. After completing this step, any application with the secret of the AAD application create above will be able to call this Finance and Operations environment and access the virtual entity functionality. +The AAD application created above will be used by Common Data Service to call Business Central apps. As such, it must be trusted by Business Central and associated with a user account with the appropriate rights in Business Central. A special service user must be created in Business Central with rights *only* to the virtual entity functionality, and no other rights. After completing this step, any application with the secret of the AAD application create above will be able to call this Business Central environment and access the virtual entity functionality. -The next steps walk through this process in Finance and Operations apps. +The next steps walk through this process in Business Central apps. -1. In Finance and Operations, go to **System Administration \> Users \> Users**. +1. In Business Central, go to **System Administration \> Users \> Users**. 2. Select **New** to add a new user. Enter the following information: @@ -109,15 +92,15 @@ The next steps walk through this process in Finance and Operations apps. - **User ID** - The user ID created above. -The next step in the process is to provide Common Data Service with the Finance and Operations instance to connect to. The following steps walk through this part of the process. +The next step in the process is to provide Common Data Service with the Business Central instance to connect to. The following steps walk through this part of the process. 1. In Common Data Service, go to **Advanced Settings \> Administration \> Virtual Entity Data Sources**. -2. Select the data source named “Finance and Operations”. +2. Select the data source named “Business Central”. 3. Fill in the information from the steps above. - - **Target URL** - The URL at which you can access Finance and Operations. + - **Target URL** - The URL at which you can access Business Central. - **OAuth URL** - https://login.windows.net/ @@ -127,17 +110,17 @@ The next step in the process is to provide Common Data Service with the Finance - **AAD Application Secret** - The secret generated above. - - **AAD Resource** - Enter 00000015-0000-0000-c000-000000000000 (this is the AAD application representing Finance and Operations, and should always be this same value). + - **AAD Resource** - Enter 00000015-0000-0000-c000-000000000000 (this is the AAD application representing Business Central, and should always be this same value). 4. Save the changes. ## Enabling virtual entities -Due to the large number of OData enabled entities available in Finance and Operations, by default, the entities are not available as virtual entities in Common Data Service. The following steps allow for enabling entities to be virtual, as needed. +Due to the large number of OData enabled entities available in Business Central, by default, the entities are not available as virtual entities in Common Data Service. The following steps allow for enabling entities to be virtual, as needed. 1. In Common Data Service, go to **Advanced find**. -2. Look for “Available Finance and Operations Entities” and select **Results**. +2. Look for “Available Business Central Entities” and select **Results**. ![Catalog](../media/fovecatalog.png) @@ -149,7 +132,7 @@ Due to the large number of OData enabled entities available in Finance and Opera ## Refreshing virtual entity metadata -The virtual entity metadata can be force-refreshed when it is expected for the entity metadata in Finance and Operations to have changed. This can be done by setting **Refresh** to **Yes** and saving. This will sync the latest entity definition from Finance and Operations to Common Data Service and update the virtual entity. +The virtual entity metadata can be force-refreshed when it is expected for the entity metadata in Business Central to have changed. This can be done by setting **Refresh** to **Yes** and saving. This will sync the latest entity definition from Business Central to Common Data Service and update the virtual entity. Referencing virtual entities ---------------------------- diff --git a/dev-itpro/powerplatform/application-lifecycle-management.md b/dev-itpro/powerplatform/application-lifecycle-management.md index c9bd1f8ce2..9f30c41010 100644 --- a/dev-itpro/powerplatform/application-lifecycle-management.md +++ b/dev-itpro/powerplatform/application-lifecycle-management.md @@ -1,30 +1,13 @@ --- -# required metadata - -title: Application lifecycle management for solutions that use virtual entities -description: This topic explains the application lifecycle for solutions that use virtual entities for Finance and Operations. -author: Sunil-Garg -manager: AnnBe -ms.date: 07/13/2020 +title: "Application lifecycle management for solutions that use virtual entities" +ms.custom: na +ms.date: 08/12/2020 +ms.reviewer: solsen +ms.suite: na +ms.tgt_pltfrm: na ms.topic: article -ms.prod: -ms.service: dynamics-ax-applications -ms.technology: - -# optional metadata - -# ms.search.form: -audience: Developer, IT Pro -# ms.devlang: -ms.reviewer: sericks -ms.search.scope: Operations -# ms.tgt_pltfrm: -# ms.custom: NotInToc -ms.search.region: Global -# ms.search.industry: -ms.author: sunilg -ms.search.validFrom: 2020-10-31 -ms.dyn365.ops.version: 10.0.0 +ms.service: "dynamics365-business-central" +author: solsen --- # Application lifecycle management for solutions that use virtual entities @@ -32,46 +15,46 @@ ms.dyn365.ops.version: 10.0.0 [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -The application lifecycle for an end-to-end solution using Finance and Operations virtual entities will encompass both Finance and Operations as well as Common Data Service. This topic explains this in detail. +The application lifecycle for an end-to-end solution using Business Central virtual entities will encompass both Business Central as well as Common Data Service. This topic explains this in detail. ## Solution management -Virtual entities for Finance and Operations don't exist in Common Data Service until they are created. Virtual entities must be created inside a solution. The MicrosoftOperationsERPVE solution is used for this purpose. This solution will contain all the virtual entities that are created from an instance of Finance and Operations. +Virtual entities for Business Central don't exist in Common Data Service until they are created. Virtual entities must be created inside a solution. The MicrosoftOperationsERPVE solution is used for this purpose. This solution will contain all the virtual entities that are created from an instance of Business Central. MicrosoftOperationsERPVE is a [managed solution](https://docs.microsoft.com/powerapps/developer/common-data-service/introduction-solutions). By definition, a managed solution can't be modified after it has been generated. However, MicrosoftOperationsERPVE is a managed solution that grants privileges to update the components (that is, virtual entities) that are inside it. Therefore, new virtual entities can be added to the solution as they are created, and existing virtual entities can be updated as required. Nevertheless, the privileges to modify the managed solution are available only to the platform itself. Users can't make changes directly to the solution. -Because MicrosoftOperationsERPVE is a managed solution, solutions from customers, partners, and independent software vendors (ISVs) can take a dependency on it. This capability allows for consistent application lifecycle management (ALM) for solutions that use and depend on the virtual entities for Finance and Operations. +Because MicrosoftOperationsERPVE is a managed solution, solutions from customers, partners, and independent software vendors (ISVs) can take a dependency on it. This capability allows for consistent application lifecycle management (ALM) for solutions that use and depend on the virtual entities for Business Central. -When a solution that depends on MicrosoftOperationsERPVE is exported, placeholders for the virtual entities that are used in the solution are added in the exported solution. When that solution is imported into another Common Data Service environment, the import process also generates the dependent Finance and Operations virtual entities in the MicrosoftOperationsERPVE solution for the Finance and Operations instance that is connected to the Common Data Service environment. Therefore, MicrosoftOperationsERPVE must already exist before a solution that depends on it is imported. Otherwise, an error message is shown. Additionally, if a dependent entity isn't available in the Finance and Operations instance, the virtual entity for that entity won't be generated. Virtual entities are generated only for entities that are available. +When a solution that depends on MicrosoftOperationsERPVE is exported, placeholders for the virtual entities that are used in the solution are added in the exported solution. When that solution is imported into another Common Data Service environment, the import process also generates the dependent Business Central virtual entities in the MicrosoftOperationsERPVE solution for the Business Central instance that is connected to the Common Data Service environment. Therefore, MicrosoftOperationsERPVE must already exist before a solution that depends on it is imported. Otherwise, an error message is shown. Additionally, if a dependent entity isn't available in the Business Central instance, the virtual entity for that entity won't be generated. Virtual entities are generated only for entities that are available. -The following list describes other solutions that Finance and Operations virtual entities require to work, and that must be available in the Common Data Service environment: +The following list describes other solutions that Business Central virtual entities require to work, and that must be available in the Common Data Service environment: -- **MicrosoftOperationsERPCatalog** – This solution provides a catalog of the available entities in a Finance and Operations instance. It also provides the connection that is used to set up a configuration. For more information, see the later sections of this topic. -- **MicrosoftOperationsVESupport** – This solution provides the virtual entity provider for Finance and Operations apps. The provider can communicate with Finance and Operations apps and Common Data Service. For more information, see the next section. -- **Dynamics365Company** – This solution adds the Company entity, which is referenced by all Finance and Operations entities that have a **PrimaryCompanyContext** metadata value. +- **MicrosoftOperationsERPCatalog** – This solution provides a catalog of the available entities in a Business Central instance. It also provides the connection that is used to set up a configuration. For more information, see the later sections of this topic. +- **MicrosoftOperationsVESupport** – This solution provides the virtual entity provider for Business Central apps. The provider can communicate with Business Central apps and Common Data Service. For more information, see the next section. +- **Dynamics365Company** – This solution adds the Company entity, which is referenced by all Business Central entities that have a **PrimaryCompanyContext** metadata value. -All these solutions must be present in an environment. Otherwise, virtual entities won't work with Finance and Operations apps. These solutions are packaged together to allow for easier portability across environments. +All these solutions must be present in an environment. Otherwise, virtual entities won't work with Business Central apps. These solutions are packaged together to allow for easier portability across environments. ## Managing entities from multiple environments -The MicrosoftOperationsVESupport solution consists of the **msdyn\_financeandoperationsvirtualentity** entity. This entity represents the virtual entity data source for Finance and Operations that captures connection setup information. Each record in this entity represents a connection to a Finance and Operations instance. +The MicrosoftOperationsVESupport solution consists of the **msdyn\_financeandoperationsvirtualentity** entity. This entity represents the virtual entity data source for Business Central that captures connection setup information. Each record in this entity represents a connection to a Business Central instance. -A catalog is used to list all the entities in a Finance and Operations instance that are available for virtualization in Common Data Service (in other words, all the entities in Finance and Operations that are enabled for Open Data Protocol \[OData\]). The catalog is part of the default MicrosoftOperationsERPCatalog solution and is applicable to a Finance and Operations instance. +A catalog is used to list all the entities in a Business Central instance that are available for virtualization in Common Data Service (in other words, all the entities in Business Central that are enabled for Open Data Protocol \[OData\]). The catalog is part of the default MicrosoftOperationsERPCatalog solution and is applicable to a Business Central instance. -Note that each Common Data Service environment must point to only one Finance and Operations instance at any time, and each Finance and Operations environment must point to only one Common Data Service environment. Therefore, there should be only one record in the **msdyn\_financeandoperationsvirtualentity** entity. +Note that each Common Data Service environment must point to only one Business Central instance at any time, and each Business Central environment must point to only one Common Data Service environment. Therefore, there should be only one record in the **msdyn\_financeandoperationsvirtualentity** entity. -The **mserp\_financeandoperationsentity** entity that represents the catalog can be queried to list the entities in a Finance and Operations instance. Because this entity is a virtual entity, the catalog is never persisted in Common Data Service. +The **mserp\_financeandoperationsentity** entity that represents the catalog can be queried to list the entities in a Business Central instance. Because this entity is a virtual entity, the catalog is never persisted in Common Data Service. -Notice that the name of the catalog entity has the "mserp\_" prefix. This prefix identifies the entities in the catalog as Finance and Operations entities. The same prefix is also added to the system names of the virtual entities that are generated for Finance and Operations in the MicrosoftOperationsERPVE solution. Therefore, the maker can distinguish Finance and Operations virtual entities from other entities. The prefix is set in the managed solution and can't be changed. +Notice that the name of the catalog entity has the "mserp\_" prefix. This prefix identifies the entities in the catalog as Business Central entities. The same prefix is also added to the system names of the virtual entities that are generated for Business Central in the MicrosoftOperationsERPVE solution. Therefore, the maker can distinguish Business Central virtual entities from other entities. The prefix is set in the managed solution and can't be changed. ### Managing entities from multiple ISV solutions -One or more ISV solutions will take a dependency on the MicrosoftOperationsERPVE solution to use virtual entities for Finance and Operations. Because custom entities in Finance and Operations use the same catalog as out-of-box entities in Finance and Operations, the virtual entities for custom Finance and Operations entities will also be generated in the MicrosoftOperationsERPVE solution. +One or more ISV solutions will take a dependency on the MicrosoftOperationsERPVE solution to use virtual entities for Business Central. Because custom entities in Business Central use the same catalog as out-of-box entities in Business Central, the virtual entities for custom Business Central entities will also be generated in the MicrosoftOperationsERPVE solution. -The established guidelines and ALM for entity development in Finance and Operations ensure that there are no conflicting entity names across ISV solutions. Therefore, no conflicts of this type can occur when virtual entities are generated in Common Data Service for custom Finance and Operations entities from multiple ISV solutions. All virtual entities for Finance and Operations entities, including custom entities, will have the "mserp\_" prefix that was mentioned earlier. +The established guidelines and ALM for entity development in Business Central ensure that there are no conflicting entity names across ISV solutions. Therefore, no conflicts of this type can occur when virtual entities are generated in Common Data Service for custom Business Central entities from multiple ISV solutions. All virtual entities for Business Central entities, including custom entities, will have the "mserp\_" prefix that was mentioned earlier. ### Managing a Finance and Operation instance in a Common Data Service environment for virtual entities -One Finance and Operations instance must be linked to a Common Data Service environment for virtual entities. The connection setup information that is required is captured in a virtual entity data source for Finance and Operations. This data source is included in the MicrosoftOperationsERPCatalog solution. +One Business Central instance must be linked to a Common Data Service environment for virtual entities. The connection setup information that is required is captured in a virtual entity data source for Business Central. This data source is included in the MicrosoftOperationsERPCatalog solution. diff --git a/dev-itpro/powerplatform/entity-modeling.md b/dev-itpro/powerplatform/entity-modeling.md index 41f4d9824e..b51ebe70f1 100644 --- a/dev-itpro/powerplatform/entity-modeling.md +++ b/dev-itpro/powerplatform/entity-modeling.md @@ -1,30 +1,13 @@ --- -# required metadata - -title: Entity modeling -description: This topic explains relational modeling concepts using virtual entities for Finance and Operations entities. -author: Sunil-Garg -manager: AnnBe -ms.date: 07/21/2020 +title: "Entity modeling" +ms.custom: na +ms.date: 08/12/2020 +ms.reviewer: solsen +ms.suite: na +ms.tgt_pltfrm: na ms.topic: article -ms.prod: -ms.service: dynamics-ax-applications -ms.technology: - -# optional metadata - -# ms.search.form: -audience: Developer, IT Pro -# ms.devlang: -ms.reviewer: sericks -ms.search.scope: Operations -# ms.tgt_pltfrm: -# ms.custom: NotInToc -ms.search.region: Global -# ms.search.industry: -ms.author: sunilg -ms.search.validFrom: 2020-05-31 -ms.dyn365.ops.version: 10.0.12 +ms.service: "dynamics365-business-central" +author: solsen --- # Entity modeling @@ -32,42 +15,42 @@ ms.dyn365.ops.version: 10.0.12 [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -> The public entity name that is exposed in Common Data Service metadata for the Finance and Operations virtual entity uses the physical name of the Finance and Operations entity. This could be different from the public name of the entity as exposed by the OData metadata in Finance and Operations apps. +> The public entity name that is exposed in Common Data Service metadata for the Business Central virtual entity uses the physical name of the Business Central entity. This could be different from the public name of the entity as exposed by the OData metadata in Business Central apps. -Building an app requires capabilities to perform relational modeling between entities that are being used in the app. In the context of virtual entities, there will be scenarios where virtual entities and native entities in Common Data Service must work together to enable the desired user experience. This topic explains concepts of relational modeling that can be implemented using virtual entities for Finance and Operations. +Building an app requires capabilities to perform relational modeling between entities that are being used in the app. In the context of virtual entities, there will be scenarios where virtual entities and native entities in Common Data Service must work together to enable the desired user experience. This topic explains concepts of relational modeling that can be implemented using virtual entities for Business Central. ## Generating virtual entities -By default, virtual entities for Finance and Operations apps don't exist in Common Data Service. A user must query the catalog entity to view the entities that are available in the linked instance of Finance and Operations. From the catalog, the user can select one or more entities, and then request that Common Data Service generate the virtual entities. This procedure is explained in later sections. +By default, virtual entities for Business Central apps don't exist in Common Data Service. A user must query the catalog entity to view the entities that are available in the linked instance of Business Central. From the catalog, the user can select one or more entities, and then request that Common Data Service generate the virtual entities. This procedure is explained in later sections. ## Entity fields -When a virtual entity is generated for a Finance and Operations entity, the system tries to create each field in the Finance and Operations entity in the corresponding virtual entity in Common Data Service. In an ideal case, the total number of fields will be the same in both entities, unless there is a mismatch in supported data types between Finance and Operations and Common Data Service. For data types that are supported, the field properties in Common Data Service are set based on the properties in Finance and Operations. +When a virtual entity is generated for a Business Central entity, the system tries to create each field in the Business Central entity in the corresponding virtual entity in Common Data Service. In an ideal case, the total number of fields will be the same in both entities, unless there is a mismatch in supported data types between Business Central and Common Data Service. For data types that are supported, the field properties in Common Data Service are set based on the properties in Business Central. This rest of this section describes supported and unsupported data types. For more information about fields in Common Data Service, see [Fields overview](https://docs.microsoft.com/powerapps/maker/common-data-service/fields-overview). -| Data type in Finance and Operations | Modeled data type in Common Data Service | +| Data type in Business Central | Modeled data type in Common Data Service | |-------------------------------------|------------------------------------------| | Real | Decimal

For information about the possible mismatch, see the next table.

| | Long | Decimal, where the precision equals 0 (zero) | | Int | Integer | | String (non-memo), String (memo) | String – single line of text, String – multiple lines of text | -| UtcDateTime | DateTime (DateTimeFormat.DateAndTime, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Finance and Operations is surfaced as a null value in Common Data Service. | -| Date | DateTime - (DateTimeFormat.DateOnly, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Finance and Operations is surfaced as an empty value in Common Data Service. | -| Enum | Picklist

Finance and Operations enumerations (enums) are generated as global OptionSets in Common Data Service. Matching between the systems is done by using the **External Name** property of values. Enum integer values in Common Data Service aren't guaranteed to be stable between the systems. Therefore, you should not rely on them, especially in the case of extensible enums in Finance and Operations, because these enums don't have a stable ID either. OptionSet metadata is updated when an entity that uses the OptionSet is updated. | +| UtcDateTime | DateTime (DateTimeFormat.DateAndTime, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Business Central is surfaced as a null value in Common Data Service. | +| Date | DateTime - (DateTimeFormat.DateOnly, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Business Central is surfaced as an empty value in Common Data Service. | +| Enum | Picklist

Business Central enumerations (enums) are generated as global OptionSets in Common Data Service. Matching between the systems is done by using the **External Name** property of values. Enum integer values in Common Data Service aren't guaranteed to be stable between the systems. Therefore, you should not rely on them, especially in the case of extensible enums in Business Central, because these enums don't have a stable ID either. OptionSet metadata is updated when an entity that uses the OptionSet is updated. | -Fields of the *real* and *long* data types in Finance and Operations are modeled as the *decimal* data type in Common Data Service. Because of the mismatch in precision and scale between the two data types, the following behavior must be considered. +Fields of the *real* and *long* data types in Business Central are modeled as the *decimal* data type in Common Data Service. Because of the mismatch in precision and scale between the two data types, the following behavior must be considered. | Use case | Resulting behavior | |----------------------------------------------|--------------------| | Common Data Service has higher precision. | This use case should never occur unless the metadata is out of sync. | -| Finance and Operations has higher precision. | During a read operation, the value is rounded to the closest precision value in Common Data Service. If the value is edited in Common Data Service, it's rounded to the closest precision value in Finance and Operations. During a write operation, the value that is specified in Common Data Service is written, because Finance and Operations supports higher precision. | +| Business Central has higher precision. | During a read operation, the value is rounded to the closest precision value in Common Data Service. If the value is edited in Common Data Service, it's rounded to the closest precision value in Business Central. During a write operation, the value that is specified in Common Data Service is written, because Business Central supports higher precision. | | Common Data Service has higher scale. | Not applicable | -| Finance and Operations has higher scale. | Common Data Service shows the Finance and Operations value, even if it exceeds 100 billion. However, there will be a loss of precision. For example, 987,654,100,000,000,000 is shown in Common Data Service as "987,654,099,999,999,900". If the value of this field is edited in Common Data Service, Common Data Service validation throws an error that the value exceeds the maximum value before that value is sent to Finance and Operations. | +| Business Central has higher scale. | Common Data Service shows the Business Central value, even if it exceeds 100 billion. However, there will be a loss of precision. For example, 987,654,100,000,000,000 is shown in Common Data Service as "987,654,099,999,999,900". If the value of this field is edited in Common Data Service, Common Data Service validation throws an error that the value exceeds the maximum value before that value is sent to Business Central. | -The following data types in Finance and Operations aren't supported in Common Data Service. Fields of these data types in Finance and Operations entities won't be made available in the corresponding virtual entities in Common Data Service. If fields of these data types are used as parameters in Open Data Protocol (OData) actions, those actions won't be available for use in the corresponding virtual entities. For more information about OData actions, see the [OData actions](#odata-actions) section later in this topic. +The following data types in Business Central aren't supported in Common Data Service. Fields of these data types in Business Central entities won't be made available in the corresponding virtual entities in Common Data Service. If fields of these data types are used as parameters in Open Data Protocol (OData) actions, those actions won't be available for use in the corresponding virtual entities. For more information about OData actions, see the [OData actions](#odata-actions) section later in this topic. - AnyType - BLOB @@ -80,15 +63,15 @@ The following data types in Finance and Operations aren't supported in Common Da - VarArg - Void (Void return types on OData actions are supported.) -Data type that are supported in Common Data Service but not in Finance and Operations aren't supported in virtual entities for Finance and Operations. +Data type that are supported in Common Data Service but not in Business Central aren't supported in virtual entities for Business Central. ## Entity key/primary key -In Finance and Operations, entities can have one or more fields of various data types as the entity key. An entity key uniquely identifies a record in a Finance and Operations entity. Additionally, a record in an entity can be uniquely identified by a record ID primary key of the Int64 type. +In Business Central, entities can have one or more fields of various data types as the entity key. An entity key uniquely identifies a record in a Business Central entity. Additionally, a record in an entity can be uniquely identified by a record ID primary key of the Int64 type. In Common Data Service, the primary key is always a globally unique identifier (GUID). The GUID-based primary key enables a record in an entity in Common Data Service to be uniquely identified. -To bridge the implementation gap between Finance and Operations and Common Data Service, the primary key of a virtual entity for Finance and Operations is a GUID (to comply with Common Data Service). This GUID consists of the data entity ID in the first 4 bytes, and the record ID of the root data source in the entity as the last 8 bytes. This design satisfies Common Data Service's requirement that a GUID be used as the entity key. It also enables the table ID and record ID to be used to uniquely identify the entity record in Finance and Operations. +To bridge the implementation gap between Business Central and Common Data Service, the primary key of a virtual entity for Business Central is a GUID (to comply with Common Data Service). This GUID consists of the data entity ID in the first 4 bytes, and the record ID of the root data source in the entity as the last 8 bytes. This design satisfies Common Data Service's requirement that a GUID be used as the entity key. It also enables the table ID and record ID to be used to uniquely identify the entity record in Business Central. ## Primary field @@ -98,31 +81,31 @@ In Common Data Service, each entity must have a primary field. This field must b - The quick view form for an entity includes the primary field. - A lookup to another entity is added to a page and shows the data from the primary field. -Based on this use of the primary field in Common Data Service, the primary field for a virtual entity for Finance and Operations is designed to use the entity key of the corresponding entity in Finance and Operations. +Based on this use of the primary field in Common Data Service, the primary field for a virtual entity for Business Central is designed to use the entity key of the corresponding entity in Business Central. -Because the primary field in Common Data Service is expected to have only one field of the string type, whereas the entity key in Finance and Operations can have multiple fields of various data types, the entity key fields are converted to strings. The strings are concatenated and separated by a pipe (\|), to a maximum length of 255 characters. Any value that exceeds 255 is truncated. This virtual entity field that represents the primary field is named **mserp\_primaryfield**. +Because the primary field in Common Data Service is expected to have only one field of the string type, whereas the entity key in Business Central can have multiple fields of various data types, the entity key fields are converted to strings. The strings are concatenated and separated by a pipe (\|), to a maximum length of 255 characters. Any value that exceeds 255 is truncated. This virtual entity field that represents the primary field is named **mserp\_primaryfield**. ## Relations > [!IMPORTANT] > A write transaction that spans a virtual entity and a native entity is not supported. We do not recommend using this form of transaction, as there is no way to ensure consistency. -Relations in Finance and Operations entities are modeled as one-to-many (1:n) or many-to-one (n:1) relations. These relations are modeled as relationships in the virtual entity in Common Data Service. Note that many-to-many (n:n) relations aren't supported in Finance and Operations. +Relations in Business Central entities are modeled as one-to-many (1:n) or many-to-one (n:1) relations. These relations are modeled as relationships in the virtual entity in Common Data Service. Note that many-to-many (n:n) relations aren't supported in Business Central. -For example, in Finance and Operations, if Entity A has a foreign key to Entity B, this relation will be modeled as an n:1 relationship in virtual entity Entity A in Common Data Service. The schema name of this relationship in Common Data Service uses the naming convention **mserp\_FK\_\\_\**. This naming convention has a maximum string length of 120 characters. Any relation where the schema name will produce a name that exceeds 120 characters won't be generated in the virtual entity in Common Data Service. +For example, in Business Central, if Entity A has a foreign key to Entity B, this relation will be modeled as an n:1 relationship in virtual entity Entity A in Common Data Service. The schema name of this relationship in Common Data Service uses the naming convention **mserp\_FK\_\\_\**. This naming convention has a maximum string length of 120 characters. Any relation where the schema name will produce a name that exceeds 120 characters won't be generated in the virtual entity in Common Data Service. -The external name of this relationship uses the naming convention **FK\_\**. The external name is used to determine the relation in Finance and Operations when the query that is sent to Finance and Operations is built. +The external name of this relationship uses the naming convention **FK\_\**. The external name is used to determine the relation in Business Central when the query that is sent to Business Central is built. -When a relationship is generated for a virtual entity in Common Data Service, a new field of the lookup type is also added to the source entity. In the preceding example, when the relationship is created, a new lookup field that uses the naming convention **mserp\_fk\_\\_id** is added to source entity Entity A. Because there can be several relations in an entity in Finance and Operations, the same number of lookup fields (one per related entity) will be created in the source virtual entity. When this lookup field is added to a page or a view, it will show the primary field value from the related entity. +When a relationship is generated for a virtual entity in Common Data Service, a new field of the lookup type is also added to the source entity. In the preceding example, when the relationship is created, a new lookup field that uses the naming convention **mserp\_fk\_\\_id** is added to source entity Entity A. Because there can be several relations in an entity in Business Central, the same number of lookup fields (one per related entity) will be created in the source virtual entity. When this lookup field is added to a page or a view, it will show the primary field value from the related entity. -A relationship in the virtual entity in Common Data Service will be generated only if the related entity in the relation already exists as a virtual entity in Common Data Service. In the preceding example, if Entity B doesn't exist as a virtual entity in Common Data Service, the relation to Entity B won't be created in Entity A when Entity A is generated as a virtual entity. This relation will be added to Entity A only when Entity B is generated as a virtual entity. Therefore, when a virtual entity is generated for Finance and Operations, validations are done to ensure that only relationships that can be complete and functional are generated in the virtual entity that is being generated. +A relationship in the virtual entity in Common Data Service will be generated only if the related entity in the relation already exists as a virtual entity in Common Data Service. In the preceding example, if Entity B doesn't exist as a virtual entity in Common Data Service, the relation to Entity B won't be created in Entity A when Entity A is generated as a virtual entity. This relation will be added to Entity A only when Entity B is generated as a virtual entity. Therefore, when a virtual entity is generated for Business Central, validations are done to ensure that only relationships that can be complete and functional are generated in the virtual entity that is being generated. -In summary, a relationship to another Finance and Operations virtual entity might not exist in the virtual entity for either of the following reasons: +In summary, a relationship to another Business Central virtual entity might not exist in the virtual entity for either of the following reasons: -- The Finance and Operations entity that is participating in the relationship doesn't exist as a virtual entity. +- The Business Central entity that is participating in the relationship doesn't exist as a virtual entity. - The length of the name of the relationship exceeds 120 characters. -Note that if an error is encountered when any part of a Finance and Operations virtual entity is generated in Common Data Service, the virtual entity won't be created at all. If relationships don't exist for either of the preceding reasons, the situation isn't considered an error. +Note that if an error is encountered when any part of a Business Central virtual entity is generated in Common Data Service, the virtual entity won't be created at all. If relationships don't exist for either of the preceding reasons, the situation isn't considered an error. ### Native entity–to–native entity relationships @@ -130,17 +113,17 @@ Native entity–to–native entity relationships are the standard Common Data Se ### Virtual entity–to–virtual entity relationships -The relationships between two Finance and Operations virtual entities are driven by the relation metadata in the Finance and Operations entities. As was explained earlier, these relations are generated as relationships in Common Data Service when the virtual entity is generated. As in the behavior for native entities in Common Data Service, these relationships use the GUID to identify the unique record of the entity in Finance and Operations. Semantically, the GUID on the Finance and Operations virtual entity behaves like the GUID on the native Common Data Service entity. For information about the implementation of the GUID in Finance and Operations virtual entities, see the [Entity key/primary key](entity-modeling.md#entity-keyprimary-key) section earlier in this topic. +The relationships between two Business Central virtual entities are driven by the relation metadata in the Business Central entities. As was explained earlier, these relations are generated as relationships in Common Data Service when the virtual entity is generated. As in the behavior for native entities in Common Data Service, these relationships use the GUID to identify the unique record of the entity in Business Central. Semantically, the GUID on the Business Central virtual entity behaves like the GUID on the native Common Data Service entity. For information about the implementation of the GUID in Business Central virtual entities, see the [Entity key/primary key](entity-modeling.md#entity-keyprimary-key) section earlier in this topic. In the preceding example, the GUID of the related entity is the entity key of Entity B and will be used to build queries to identify a record in Finance and Operation. The relation that Entity A has to Entity B will be used. -Therefore, in effect, the entity name is the only information that is used in a relation that comes from Finance and Operations. The entity name gives access to the primary field in the related entity, so that it can be shown in the lookup. It also gives access to the GUID of the related entity, so that it can be used in other queries, as was explained earlier. The actual field that the relation is built on in the Finance and Operations entity isn't used at all. +Therefore, in effect, the entity name is the only information that is used in a relation that comes from Business Central. The entity name gives access to the primary field in the related entity, so that it can be shown in the lookup. It also gives access to the GUID of the related entity, so that it can be used in other queries, as was explained earlier. The actual field that the relation is built on in the Business Central entity isn't used at all. ### Virtual entity–to–native entity relationship -As was explained earlier, the GUID is the only information that is used to uniquely identify a record in a native Common Data Service entity (including in native entity–to–native entity relationships) or in a Finance and Operations virtual entity (including in virtual entity–to–virtual entity relationships). However, consider an example where you want to show sales orders from Finance and Operations for Account A in Common Data Service. The query that is sent to Finance and Operations for this relationship will have a WHERE clause on the GUID of the entity key of the native accounts entity in Common Data Service, because the sales orders must be filtered for a specific account in Common Data Service. However, because Finance and Operations doesn't have any information about the GUID of the entity in Common Data Service, the query won't return any sales orders. The query will be successful only if the WHERE clause has conditions that are based on the fields that Finance and Operations understands. +As was explained earlier, the GUID is the only information that is used to uniquely identify a record in a native Common Data Service entity (including in native entity–to–native entity relationships) or in a Business Central virtual entity (including in virtual entity–to–virtual entity relationships). However, consider an example where you want to show sales orders from Business Central for Account A in Common Data Service. The query that is sent to Business Central for this relationship will have a WHERE clause on the GUID of the entity key of the native accounts entity in Common Data Service, because the sales orders must be filtered for a specific account in Common Data Service. However, because Business Central doesn't have any information about the GUID of the entity in Common Data Service, the query won't return any sales orders. The query will be successful only if the WHERE clause has conditions that are based on the fields that Business Central understands. -Therefore, how can the GUID of the accounts entity in Common Data Service be replaced with fields that are in Finance and Operations, in such a way that the query that is sent to Finance and Operations will return the correct list of sales orders? +Therefore, how can the GUID of the accounts entity in Common Data Service be replaced with fields that are in Business Central, in such a way that the query that is sent to Business Central will return the correct list of sales orders? To solve this issue and enable a rich set of scenarios that allows for virtual entity–to–native entity relationships, relationships can be added to this type of entity. The relation will appear as a relationship when the virtual entity is synced. @@ -168,31 +151,31 @@ The field mapping indicates which field on the virtual entity maps to the field ``` The next step is to generate or refresh the virtual entity to get the new relationship. Note that relationships between a virtual entity and a native entity cannot be updated in Common Data Service once it is created. The only way to make an update is to physically remove the relationship, refresh the entity, and then physically re-add the relationship in order to resolve the issue. -This relationship looks like a typical GUID-based relationship, but has extra metadata to translate query filters on the relationship into restrictions on the backing fields. The query that is now generated will have a WHERE clause that is based on the fields that Finance and Operations apps recognize. That query will then return the filtered list of sales orders, as expected. +This relationship looks like a typical GUID-based relationship, but has extra metadata to translate query filters on the relationship into restrictions on the backing fields. The query that is now generated will have a WHERE clause that is based on the fields that Business Central apps recognize. That query will then return the filtered list of sales orders, as expected. ### Native entity–to–virtual entity relationships -Native entity–to–virtual entity relationships works much like native entity–to–native entity relationships. Users associate native records with virtual records in Finance and Operations, and the GUID of the virtual entity is saved on the native entity record. As was explained earlier, the entities that participate in a relationship will have the GUID field of the related entity on them. Therefore, when a quotation in Common Data Service is associated with a customer in a Finance and Operations virtual entity, the GUID of the customer virtual entity will be saved in the quotation entity. This behavior enables records to be retrieved as expected, by using standard Common Data Service functionality. +Native entity–to–virtual entity relationships works much like native entity–to–native entity relationships. Users associate native records with virtual records in Business Central, and the GUID of the virtual entity is saved on the native entity record. As was explained earlier, the entities that participate in a relationship will have the GUID field of the related entity on them. Therefore, when a quotation in Common Data Service is associated with a customer in a Business Central virtual entity, the GUID of the customer virtual entity will be saved in the quotation entity. This behavior enables records to be retrieved as expected, by using standard Common Data Service functionality. ## Enums -Enums in Finance and Operations are modeled as OptionSets in Common Data Service. When a virtual entity for Finance and Operations is generated, the required enums are generated as OptionSets. If an OptionSet already exists, it's used instead. +Enums in Business Central are modeled as OptionSets in Common Data Service. When a virtual entity for Business Central is generated, the required enums are generated as OptionSets. If an OptionSet already exists, it's used instead. ## Company -An entity in Finance and Operations can be bound to a company, or it can be global. The virtual entity for a Finance and Operations entity that is bound to a company will have a relationship to the cdm\_company entity in Common Data Service. The cdm\_company entity is a native entity in Common Data Service and is part of the Dynamics365Company solution. As always, when a relationship is created, a lookup field is also created in the virtual entity for the related entity (cdm\_company in this case). This lookup field is named **Company**, and it must be used to provide an optimal user experience where users can select a value in a list or go to the details of the related record. A field that is named **Company Code** is also added in the virtual entity. The value is a four-character string. This field must be used in programming. +An entity in Business Central can be bound to a company, or it can be global. The virtual entity for a Business Central entity that is bound to a company will have a relationship to the cdm\_company entity in Common Data Service. The cdm\_company entity is a native entity in Common Data Service and is part of the Dynamics365Company solution. As always, when a relationship is created, a lookup field is also created in the virtual entity for the related entity (cdm\_company in this case). This lookup field is named **Company**, and it must be used to provide an optimal user experience where users can select a value in a list or go to the details of the related record. A field that is named **Company Code** is also added in the virtual entity. The value is a four-character string. This field must be used in programming. ## Attachments -Attachments in Finance and Operations entities are supported on a per-entity basis. For example, an invoice header entity will implement an invoice-related attachments entity to [enable attachments via entities](../../fin-ops/organization-administration/configure-document-management.md#how-can-attachments-be-extracted-from-the-system). +Attachments in Business Central entities are supported on a per-entity basis. For example, an invoice header entity will implement an invoice-related attachments entity to [enable attachments via entities](../../fin-ops/organization-administration/configure-document-management.md#how-can-attachments-be-extracted-from-the-system). -Entities of this type will have relations with the corresponding attachments entity in Finance and Operations. Therefore, they will follow the same pattern as the other relations that were discussed earlier. In other words, Finance and Operations entities that have implemented attachments functionality will also make attachments available by using virtual entities. Finance and Operations entities that don't support attachments also won't support attachments when they are virtualized in Common Data Service. +Entities of this type will have relations with the corresponding attachments entity in Business Central. Therefore, they will follow the same pattern as the other relations that were discussed earlier. In other words, Business Central entities that have implemented attachments functionality will also make attachments available by using virtual entities. Business Central entities that don't support attachments also won't support attachments when they are virtualized in Common Data Service. -Note that Finance and Operations virtual entities support only the reading of attachments. They don't currently support the creation, update, or deletion of attachments by using virtual entities. +Note that Business Central virtual entities support only the reading of attachments. They don't currently support the creation, update, or deletion of attachments by using virtual entities. ## OData actions -OData actions in the Finance and Operations entities are made available as custom actions in Common Data Service. For more information about custom actions and what they enable in Common Data Service, see [Custom actions](https://docs.microsoft.com/powerapps/developer/common-data-service/custom-actions). +OData actions in the Business Central entities are made available as custom actions in Common Data Service. For more information about custom actions and what they enable in Common Data Service, see [Custom actions](https://docs.microsoft.com/powerapps/developer/common-data-service/custom-actions). Input and output parameters of the following types are supported. If an input or output parameter is of a different type, the OData action doesn't appear as the SDK message in Common Data Service. @@ -202,7 +185,7 @@ Input and output parameters of the following types are supported. If an input or - Boolean - Date/Datetime -Here are some examples of OData actions that are supported in Finance and Operations entities, but that aren't supported in the corresponding virtual entities in Common Data Service: +Here are some examples of OData actions that are supported in Business Central entities, but that aren't supported in the corresponding virtual entities in Common Data Service: - RetailStoreTenderTypeTable.queryDistinctTenderTypeIdAndName (a collection of RetailStoreTenderTypeTable entity) - DocumentRoutingClientApp.syncPrinters (DocumentRoutingClientApp entity) @@ -211,14 +194,14 @@ Here are some examples of OData actions that are supported in Finance and Operat ## Labels and localization -Labels that are defined on metadata, such as entity names and field names in Finance and Operations, are retrieved when virtual entities are generated in Common Data Service. The labels are retrieved by passing the list of language locales that are installed in Common Data Service. Finance and Operations returns each label as a list of locale/value sets that are then used to construct a label instance in Common Data Service. Only the language packs that exist at the time of entity generation or update are included. Additionally, only labels that Finance and Operations has provided a translation for are included. Any missing translations revert to the label ID, such as **\@SYS:DataEntity**. After a new language pack is installed in Common Data Service, existing entities must be updated to pick up the new label information, if labels in that language exist in Finance and Operations. +Labels that are defined on metadata, such as entity names and field names in Business Central, are retrieved when virtual entities are generated in Common Data Service. The labels are retrieved by passing the list of language locales that are installed in Common Data Service. Business Central returns each label as a list of locale/value sets that are then used to construct a label instance in Common Data Service. Only the language packs that exist at the time of entity generation or update are included. Additionally, only labels that Business Central has provided a translation for are included. Any missing translations revert to the label ID, such as **\@SYS:DataEntity**. After a new language pack is installed in Common Data Service, existing entities must be updated to pick up the new label information, if labels in that language exist in Business Central. -Any runtime labels are returned in the language of the current user context. In other words, they are returned in the language that is specified on that user's UserInfo record in Finance and Operations. This behavior also applies to error messages. +Any runtime labels are returned in the language of the current user context. In other words, they are returned in the language that is specified on that user's UserInfo record in Business Central. This behavior also applies to error messages. ## Error handling -Finance and Operations create, read, update, and delete (CRUD) business logic on entities and backing tables is run when it's called through the virtual entity in Common Data Service. If any exception is thrown on the Finance and Operations side, the last message in the error log is returned to Common Data Service and is thrown as an InvalidPluginExecutionException exception that contains the message from Finance and Operations. Because the Finance and Operations code runs in the context of the user, the language of the error message is based on the language that is specified on the UserInfo record in Finance and Operations. If any messages that are written to the info log in Finance and Operations don't result in an exception, they aren't shown in Common Data Service. +Business Central create, read, update, and delete (CRUD) business logic on entities and backing tables is run when it's called through the virtual entity in Common Data Service. If any exception is thrown on the Business Central side, the last message in the error log is returned to Common Data Service and is thrown as an InvalidPluginExecutionException exception that contains the message from Business Central. Because the Business Central code runs in the context of the user, the language of the error message is based on the language that is specified on the UserInfo record in Business Central. If any messages that are written to the info log in Business Central don't result in an exception, they aren't shown in Common Data Service. ## Calculated/unmapped fields -Calculated and unmapped fields in Finance and Operations entities are also available in the corresponding virtual entities in Common Data Service. +Calculated and unmapped fields in Business Central entities are also available in the corresponding virtual entities in Common Data Service. diff --git a/dev-itpro/powerplatform/faq.md b/dev-itpro/powerplatform/faq.md index ebb762aefd..237f04437a 100644 --- a/dev-itpro/powerplatform/faq.md +++ b/dev-itpro/powerplatform/faq.md @@ -1,46 +1,29 @@ --- -# required metadata - -title: Finance and Operations virtual entities FAQ -description: This topic is a list of frequently asked questions about Finance and Operations virtual entities. -author: Sunil-Garg -manager: AnnBe -ms.date: 07/13/2020 +title: "Business Central virtual entities FAQ" +ms.custom: na +ms.date: 08/12/2020 +ms.reviewer: solsen +ms.suite: na +ms.tgt_pltfrm: na ms.topic: article -ms.prod: -ms.service: dynamics-ax-applications -ms.technology: - -# optional metadata - -# ms.search.form: -audience: Developer, IT Pro -# ms.devlang: -ms.reviewer: sericks -ms.search.scope: Operations -# ms.tgt_pltfrm: -# ms.custom: NotInToc -ms.search.region: Global -# ms.search.industry: -ms.author: sunilg -ms.search.validFrom: 2020-05-31 -ms.dyn365.ops.version: 10.0.12 +ms.service: "dynamics365-business-central" +author: solsen --- -# Finance and Operations virtual entities FAQ +# Business Central virtual entities FAQ [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -This topic is a collection of frequently asked questions about Finance and Operations virtual entities. +This topic is a collection of frequently asked questions about Business Central virtual entities. -### Do Tier 1 Finance and Operations environments or demo topologies work? +### Do Tier 1 Business Central environments or demo topologies work? Yes, Tier 1 and DEVTEST and DEMO topologies should work. -### What version of Finance and Operations do I need? +### What version of Business Central do I need? 10.0.12 is the minimum version that is required. @@ -48,33 +31,33 @@ Yes, Tier 1 and DEVTEST and DEMO topologies should work. Yes. The virtual entities are all generated in the MicrosoftOperationsERPVE solution, which isAPI-managed In other words, the items in the solution change as you make entities visible or hidden, but the solution is still a managed solution that you can take dependency on. The standard ALM flow just takes a standard reference to a virtual entity from this solution with the **Add existing** option in the ISV solution. Missing dependency of the solution will be checked when the solution is imported and during import, if a specified virtual entity doesn't yet exist, the virtual entity is automatically made visible. -### Which entities from Finance and Operations do users see in the catalog in Common Data Service? +### Which entities from Business Central do users see in the catalog in Common Data Service? Generally, users see all entities where **IsPublic** is set to **Yes**. These entities are the same entities that are currently visible in Open Data Protocol (OData). -### Do all Microsoft Power Platform users have to be users in Finance and Operations? +### Do all Microsoft Power Platform users have to be users in Business Central? -Any user of Microsoft Power Platform who tries to access Finance and Operations data through a virtual entity must also exist as a user in Finance and Operations. Therefore, technically, not *all* users have to be users in Finance and Operations. Only those users who access Finance and Operations data through virtual entities must be users in Finance and Operations. +Any user of Microsoft Power Platform who tries to access Business Central data through a virtual entity must also exist as a user in Business Central. Therefore, technically, not *all* users have to be users in Business Central. Only those users who access Business Central data through virtual entities must be users in Business Central. ### Where do I find the catalog entity? -In the **Advanced find** window, the entity is named **Available Finance and Operations Entities**. +In the **Advanced find** window, the entity is named **Available Business Central Entities**. ### Is there a way to specify a company when I perform data operations on a virtual entity? -Yes. Although the company is implicit in Finance and Operations, it's an explicit field on each company-striped entity in Common Data Service. You can use either the **Company Code** field, where the value is a four-character string, or the **Company** field, which is a lookup to cdm\_Company. Both approaches provide the same information. +Yes. Although the company is implicit in Business Central, it's an explicit field on each company-striped entity in Common Data Service. You can use either the **Company Code** field, where the value is a four-character string, or the **Company** field, which is a lookup to cdm\_Company. Both approaches provide the same information. ### Can I change the prefix for the virtual entities? -No. All Finance and Operations virtual entities should be generated in the MicrosoftOperationsERPVE solution, and they should all have the "mserp\_" prefix. This prefix should not be changed. If you have a scenario where you believe the prefix has to be changed, you should share that scenario with Microsoft. +No. All Business Central virtual entities should be generated in the MicrosoftOperationsERPVE solution, and they should all have the "mserp\_" prefix. This prefix should not be changed. If you have a scenario where you believe the prefix has to be changed, you should share that scenario with Microsoft. ### How can I filter data in an app that is created by using Power Apps, based on the current user or any other dynamic criteria, such as today-10? You can write a pre-operation plug-in on the RetrieveMultiple message of the entity and change the criteria on the query in it. Alternatively, you can write a post-operation plug-in to filter the results before they are returned. -### Can I pin a model-driven app into Finance and Operations? +### Can I pin a model-driven app into Business Central? -No, it isn't currently possible to pin a model-driven app into Finance and Operations. +No, it isn't currently possible to pin a model-driven app into Business Central. ### How can I show, in the same grid, data from multiple virtual entities that are joined to a physical entity record in Common Data Service? @@ -94,17 +77,17 @@ As in the previous Power Apps user interface (UI), you must redo the **Add Exist Yes. Here is the order of calls: 1. Common Data Service sends a create or update message. -2. All the existing logic on the Finance and Operations entity and backing tables is invoked. This logic includes default value entry that might change values. +2. All the existing logic on the Business Central entity and backing tables is invoked. This logic includes default value entry that might change values. 3. Common Data Service sends another Retrieve (single) message to get the latest copy of the data, including any fields that default values were entered for. -### Can I debug Finance and Operations when we do a create, read, update, and delete (CRUD) operation from Common Data Service? If so, which process do I have to attach? +### Can I debug Business Central when we do a create, read, update, and delete (CRUD) operation from Common Data Service? If so, which process do I have to attach? -Yes, to debug in Finance and Operations, open Visual Studio as an admin. Typically, Finance and Operations apps run under w3wp.exe as a process. However, when you open Visual Studio as an admin, IISExpress.exe is automatically opened, and Finance and Operations is hosted there. You can attach to IISExpress.exe (or to w3wp.exe if not running Visual Studio as an admin). To set breakpoints in the virtual entity code, find the **CDSVirtualEntityAdapter** and **CDSVirtualEntityController** classes. The adapter class is the first class that is called, and it only does serialization/deserialization. It then delegates to the controller class to do the actual queries. Therefore, the controller class is usually the easiest place to put breakpoints. +Yes, to debug in Business Central, open Visual Studio as an admin. Typically, Business Central apps run under w3wp.exe as a process. However, when you open Visual Studio as an admin, IISExpress.exe is automatically opened, and Business Central is hosted there. You can attach to IISExpress.exe (or to w3wp.exe if not running Visual Studio as an admin). To set breakpoints in the virtual entity code, find the **CDSVirtualEntityAdapter** and **CDSVirtualEntityController** classes. The adapter class is the first class that is called, and it only does serialization/deserialization. It then delegates to the controller class to do the actual queries. Therefore, the controller class is usually the easiest place to put breakpoints. -### Does the form business logic in Finance and Operations get called through virtual entities? +### Does the form business logic in Business Central get called through virtual entities? -Finance and Operations business logic that resides on forms isn't invoked through virtual entities. Instead, you should expect the same behavior that you get through OData access to the same entities. The expectation is that an entity that is exposed to OData (that is, **IsPublic** is set to **Yes**) has appropriate protections to ensure that data can't be corrupted. If any entity lacks this protection, that situation represents a bug in the entity. If you see differences in entity behavior between OData and virtual entities, that situation represents a bug in the virtual entity feature. +Business Central business logic that resides on forms isn't invoked through virtual entities. Instead, you should expect the same behavior that you get through OData access to the same entities. The expectation is that an entity that is exposed to OData (that is, **IsPublic** is set to **Yes**) has appropriate protections to ensure that data can't be corrupted. If any entity lacks this protection, that situation represents a bug in the entity. If you see differences in entity behavior between OData and virtual entities, that situation represents a bug in the virtual entity feature. -### If I develop a new Finance and Operations entity and want to see it in Common Data Service, do I have to select Refresh entity list in Finance and Operations? Do I have to do anything in Common Data Service? +### If I develop a new Business Central entity and want to see it in Common Data Service, do I have to select Refresh entity list in Business Central? Do I have to do anything in Common Data Service? In theory, no, you don't have to refresh the entity list. At most, you might have to either reset Internet Information Services (IIS) or restart IIS Express, depending on where Application Object Server (AOS) is running. The fact that the list of entities is accurate is cached in SysGlobalObjectCache, which is a per-process cache. Any time that this cache doesn't indicate that the list is accurate, the list is rebuilt. The rebuild process takes about five seconds. Therefore, when you restart your AOS process (w3wp.exe or iisexpress.exe), the list will be accurate the next time that you query it from Common Data Service. Additionally, although recompilation *should* flush the SysGlobalObjectCache cache, it might not. In that case, an AOS restart will flush it. diff --git a/dev-itpro/powerplatform/overview.md b/dev-itpro/powerplatform/overview.md index d161453915..193b0b0b26 100644 --- a/dev-itpro/powerplatform/overview.md +++ b/dev-itpro/powerplatform/overview.md @@ -1,44 +1,27 @@ --- -# required metadata - -title: Microsoft Power Platform integration with Finance and Operations -description: This topic describes virtual entities for Finance and Operations in Common Data Service. -author: Sunil-Garg -manager: AnnBe -ms.date: 07/13/2020 +title: "Microsoft Power Platform integration with Business Central" +ms.custom: na +ms.date: 08/12/2020 +ms.reviewer: solsen +ms.suite: na +ms.tgt_pltfrm: na ms.topic: article -ms.prod: -ms.service: dynamics-ax-applications -ms.technology: - -# optional metadata - -# ms.search.form: -audience: Developer, IT Pro -# ms.devlang: -ms.reviewer: sericks -ms.search.scope: Operations -# ms.tgt_pltfrm: -# ms.custom: NotInToc -ms.search.region: Global -# ms.search.industry: -ms.author: sunilg -ms.search.validFrom: 2020-10-31 -ms.dyn365.ops.version: 10.0.0 +ms.service: "dynamics365-business-central" +author: solsen --- -# Microsoft Power Platform integration with Finance and Operations +# Microsoft Power Platform integration with Business Central [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -Finance and Operations is a virtual data source in Common Data Service, and enables full create, read, update, delete (CRUD) operations from Common Data Service and Microsoft Power Platform. By definition, the data for virtual entities doesn't reside in Common Data Service. Instead, it continues to reside in the application where it belongs. To enable CRUD operations on Finance and Operations entities from Common Data Service, entities must be made available as virtual entities in Common Data Service. The allows CRUD operations to be performed, from Common Data Service and Microsoft Power Platform, on data that resides in Finance and Operations apps. +Business Central is a virtual data source in Common Data Service, and enables full create, read, update, delete (CRUD) operations from Common Data Service and Microsoft Power Platform. By definition, the data for virtual entities doesn't reside in Common Data Service. Instead, it continues to reside in the application where it belongs. To enable CRUD operations on Business Central entities from Common Data Service, entities must be made available as virtual entities in Common Data Service. The allows CRUD operations to be performed, from Common Data Service and Microsoft Power Platform, on data that resides in Business Central apps. ## Prerequisite reading -To understand the architecture of virtual entities for Finance and Operations apps, you must understand how Common Data Service and virtual entities work. Therefore, the following documentation is a prerequisite: +To understand the architecture of virtual entities for Business Central apps, you must understand how Common Data Service and virtual entities work. Therefore, the following documentation is a prerequisite: - [What is Common Data Service?](https://docs.microsoft.com/powerapps/maker/common-data-service/data-platform-intro) - [Entity overview](https://docs.microsoft.com/powerapps/maker/common-data-service/entity-overview) @@ -47,18 +30,18 @@ To understand the architecture of virtual entities for Finance and Operations ap - [What is Power Apps portals?](https://docs.microsoft.com/powerapps/maker/portals/overview) - [Overview of creating apps in Power Apps](https://docs.microsoft.com/powerapps/maker/) -## Virtual entities for Finance and Operations apps +## Virtual entities for Business Central apps -All Open Data Protocol (OData) entities in Finance and Operations are available as virtual entities in Common Data Service, and therefore also in Power Platform. Makers can now build experiences in customer engagement apps with data directly from Finance and Operations with full CRUD capability and without copying to Common Data Service. Power Apps Portals can be used to build external-facing websites that enable collaboration scenarios for business processes in Finance and Operations. +All Open Data Protocol (OData) entities in Business Central are available as virtual entities in Common Data Service, and therefore also in Power Platform. Makers can now build experiences in customer engagement apps with data directly from Business Central with full CRUD capability and without copying to Common Data Service. Power Apps Portals can be used to build external-facing websites that enable collaboration scenarios for business processes in Business Central. ## Architecture -Virtual entities are a Common Data Service concept that is useful beyond Finance and Operations. The following illustration shows how the Finance and Operations provider for virtual entities is implemented. Six primary methods are implemented by the provider. The first five methods are the standard CRUD operations: **Create**, **Update**, **Delete**, **Retrieve**, and **RetrieveMultiple**. The last method, **PerformAction**, is used to call OData actions, as described later in this topic. Calls to the Finance and Operations Virtual Entity Data Provider (shown as "VE Plugin" in the illustration) will cause a Secure Sockets Layer (SSL)/Transport Layer Security (TLS) 1.2 secure web call to the CDSVirtualEntityService web API endpoint of Finance and Operations. This web service then converts the queries into calls to the associated physical entities in Finance and Operations, and invokes CRUD or OData operations on those entities. Because a Finance and Operations entity is directly invoked in all operations, any business logic on the entity or its backing tables is also invoked. +Virtual entities are a Common Data Service concept that is useful beyond Business Central. The following illustration shows how the Business Central provider for virtual entities is implemented. Six primary methods are implemented by the provider. The first five methods are the standard CRUD operations: **Create**, **Update**, **Delete**, **Retrieve**, and **RetrieveMultiple**. The last method, **PerformAction**, is used to call OData actions, as described later in this topic. Calls to the Business Central Virtual Entity Data Provider (shown as "VE Plugin" in the illustration) will cause a Secure Sockets Layer (SSL)/Transport Layer Security (TLS) 1.2 secure web call to the CDSVirtualEntityService web API endpoint of Business Central. This web service then converts the queries into calls to the associated physical entities in Business Central, and invokes CRUD or OData operations on those entities. Because a Business Central entity is directly invoked in all operations, any business logic on the entity or its backing tables is also invoked. -[![Architecture of virtual entities for Finance and Operations apps](../media/fovearchitecture.png)](../media/fovearchitecture.png) +[![Architecture of virtual entities for Business Central apps](../media/fovearchitecture.png)](../media/fovearchitecture.png) -During calls, there are two points of translation from Common Data Service to Finance and Operations apps. The first point of translation occurs in the VE Plugin, which translates concepts such as entity physical names into Finance and Operations entity names. It also converts some well-known concepts, such as Company references. The web service call still uses the EntityCollection, Entity, and QueryExpression objects to express the operations that are performed, by using the translated entity names and concepts from the VE Plugin. Finally, the CDSVirtualEntityAdapterService web API in Finance and Operations completes the translation from QueryExpression to QueryBuildDataSource and other internal Finance and Operations language constructs. +During calls, there are two points of translation from Common Data Service to Business Central apps. The first point of translation occurs in the VE Plugin, which translates concepts such as entity physical names into Business Central entity names. It also converts some well-known concepts, such as Company references. The web service call still uses the EntityCollection, Entity, and QueryExpression objects to express the operations that are performed, by using the translated entity names and concepts from the VE Plugin. Finally, the CDSVirtualEntityAdapterService web API in Business Central completes the translation from QueryExpression to QueryBuildDataSource and other internal Business Central language constructs. -All calls between Common Data Service and Finance and Operations as part of virtual entities are done as service-to-service (S2S) calls by using the Azure Active Directory (Azure AD) application that is specified in the configuration. The user of this application should have access *only* to the CDSVirtualEntityAdapterService web API and the Catalog entity, CDSVirtualEntityListEntity. These privileges are included in the out-of-box security role that is named CDSVirtualEntityApplication. During the S2S calls, Common Data Service provides the identity of the user in Common Data Service who is invoking the action. The CDSVirtualEntityAdapterService web API looks up the associated user in Finance and Operations and runs the query in the context of that user. Therefore, the S2S call doesn't have to have explicit access to all the Finance and Operations entities. Instead, it can rely on the privileges of the user who is invoking the action to determine data access. +All calls between Common Data Service and Business Central as part of virtual entities are done as service-to-service (S2S) calls by using the Azure Active Directory (Azure AD) application that is specified in the configuration. The user of this application should have access *only* to the CDSVirtualEntityAdapterService web API and the Catalog entity, CDSVirtualEntityListEntity. These privileges are included in the out-of-box security role that is named CDSVirtualEntityApplication. During the S2S calls, Common Data Service provides the identity of the user in Common Data Service who is invoking the action. The CDSVirtualEntityAdapterService web API looks up the associated user in Business Central and runs the query in the context of that user. Therefore, the S2S call doesn't have to have explicit access to all the Business Central entities. Instead, it can rely on the privileges of the user who is invoking the action to determine data access. -Power Apps Portal can also access virtual entities. Because Power Apps Portal authorization is based on contact records, a mapping between contact records and Finance and Operations users is maintained in the msdyn\_externalportalusermapping table in Common Data Service. This table should be editable only by highly privileged users in Common Data Service, who have the rights to control the security access of portal users to Finance and Operations virtual entities. Any Finance and Operations user who is set up for Power Apps Portal access must have the CDSVirtualEntityAuthorizedPortalUser security role assigned, and can't have the System administrator or Security administrator role assigned. Regardless of the Power Apps Portal security setting that is applied to virtual entities, the resulting query to Finance and Operations apps is always run as the associated Finance and Operations user, and is subject to that user's entity and row security settings. Anonymous portal access is also supported. For information about this type of access and how it can be done, see [Power Apps Portal reference](power-portal-reference.md). +Power Apps Portal can also access virtual entities. Because Power Apps Portal authorization is based on contact records, a mapping between contact records and Business Central users is maintained in the msdyn\_externalportalusermapping table in Common Data Service. This table should be editable only by highly privileged users in Common Data Service, who have the rights to control the security access of portal users to Business Central virtual entities. Any Business Central user who is set up for Power Apps Portal access must have the CDSVirtualEntityAuthorizedPortalUser security role assigned, and can't have the System administrator or Security administrator role assigned. Regardless of the Power Apps Portal security setting that is applied to virtual entities, the resulting query to Business Central apps is always run as the associated Business Central user, and is subject to that user's entity and row security settings. Anonymous portal access is also supported. For information about this type of access and how it can be done, see [Power Apps Portal reference](power-portal-reference.md). diff --git a/dev-itpro/powerplatform/power-portal-reference.md b/dev-itpro/powerplatform/power-portal-reference.md index f56fe8aa84..0b146811f3 100644 --- a/dev-itpro/powerplatform/power-portal-reference.md +++ b/dev-itpro/powerplatform/power-portal-reference.md @@ -1,53 +1,36 @@ --- -# required metadata - -title: Power Apps portals with Finance and Operations -description: This topic explains how Power Apps portals can be used with Finance and Operations. -author: Sunil-Garg -manager: AnnBe -ms.date: 07/13/2020 +title: "Power Apps portals with Business Central" +ms.custom: na +ms.date: 08/12/2020 +ms.reviewer: solsen +ms.suite: na +ms.tgt_pltfrm: na ms.topic: article -ms.prod: -ms.service: dynamics-ax-applications -ms.technology: - -# optional metadata - -# ms.search.form: -audience: Developer, IT Pro -# ms.devlang: -ms.reviewer: sericks -ms.search.scope: Operations -# ms.tgt_pltfrm: -# ms.custom: NotInToc -ms.search.region: Global -# ms.search.industry: -ms.author: sunilg -ms.search.validFrom: 2020-05-31 -ms.dyn365.ops.version: 10.0.12 +ms.service: "dynamics365-business-central" +author: solsen --- -# Power Apps portals with Finance and Operations +# Power Apps portals with Business Central [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Finance and Operations apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -Power Apps portals will enable create, update, and delete (CRUD) operations to Finance and Operations entities that are available as virtual entities in Common Data Service. This topic explains the scenarios that are implemented in Power Apps portals for Finance and Operations apps. +Power Apps portals will enable create, update, and delete (CRUD) operations to Business Central entities that are available as virtual entities in Common Data Service. This topic explains the scenarios that are implemented in Power Apps portals for Business Central apps. ## Anonymous access from Power Apps portals -Collaboration scenarios in business processes such as bidding or onboarding of prospects in Finance and Operations require that external users participate from the Power Apps portal, even though they aren't users in Finance and Operations apps. The simplicity of anonymous access is appealing in these types of scenarios because the users, who might not be Finance and Operations apps users, don't have to sign in. However, they are expected to perform CRUD operations in Finance and Operations to complete any meaningful tasks in the business processes. +Collaboration scenarios in business processes such as bidding or onboarding of prospects in Business Central require that external users participate from the Power Apps portal, even though they aren't users in Business Central apps. The simplicity of anonymous access is appealing in these types of scenarios because the users, who might not be Business Central apps users, don't have to sign in. However, they are expected to perform CRUD operations in Business Central to complete any meaningful tasks in the business processes. -To ensure that only the required entities are enabled for anonymous access, a user in Finance and Operations must be designated as the user who is used for anonymous access. This designation is configured in the **Anonymous portal access user ID** field on the **Virtual entity** tab on the **System parameters** page (**System administration \> System parameters**). The designated user can then be assigned to duties and security roles to control access to specific data that must be made available to all users who will interact anonymously from the Power Portal. +To ensure that only the required entities are enabled for anonymous access, a user in Business Central must be designated as the user who is used for anonymous access. This designation is configured in the **Anonymous portal access user ID** field on the **Virtual entity** tab on the **System parameters** page (**System administration \> System parameters**). The designated user can then be assigned to duties and security roles to control access to specific data that must be made available to all users who will interact anonymously from the Power Portal. Note that because this scenario involves anonymous access, the only user context that matters, from a security perspective, is the user who is designated in the **Anonymous portal access user ID** field. ## Authenticated access from Power Apps portals -Fully authenticated user access from Power Apps portals to Finance and Operations lets users in Finance and Operations also interact from Power Apps portals. A user who signs in to the Power Apps portal is also a known user in Finance and Operations who has appropriate security roles based on job requirements. These roles govern the security access to data for the authenticated user in Power Portal. In addition, any Finance and Operations user that is expected to also use Power Apps portal to access Finance and Operations data must also belong to the **CDSVirtualEntityAuthenticatedPortalUser** security role. This provides an additional layer of security and also provides a way to know the total users that are authorized to access from Power Apps portals. +Fully authenticated user access from Power Apps portals to Business Central lets users in Business Central also interact from Power Apps portals. A user who signs in to the Power Apps portal is also a known user in Business Central who has appropriate security roles based on job requirements. These roles govern the security access to data for the authenticated user in Power Portal. In addition, any Business Central user that is expected to also use Power Apps portal to access Business Central data must also belong to the **CDSVirtualEntityAuthenticatedPortalUser** security role. This provides an additional layer of security and also provides a way to know the total users that are authorized to access from Power Apps portals. -Because Power Apps portals authentication is linked to the Contacts entity in Common Data Service, a mapping must be established between the Common Data Service contact and the corresponding user in Finance and Operations. This mapping can be done by adding entries to the **msdyn\_externalportalusermapping** entity. From a security perspective, the scope of virtual entities that are made available to authenticated users must be configured as **Global** in the Power Apps portal. +Because Power Apps portals authentication is linked to the Contacts entity in Common Data Service, a mapping must be established between the Common Data Service contact and the corresponding user in Business Central. This mapping can be done by adding entries to the **msdyn\_externalportalusermapping** entity. From a security perspective, the scope of virtual entities that are made available to authenticated users must be configured as **Global** in the Power Apps portal. -When authenticated users from a different tenant need to be added to Finance and Operations as users, you must use the [Create new user](../sysadmin/tasks/create-new-users.md) process in Finance and Operations. This process adds cross-tenant users as Microsoft Azure Active Directory (Azure AD) business-to-business (B2B) guest users. +When authenticated users from a different tenant need to be added to Business Central as users, you must use the [Create new user](../sysadmin/tasks/create-new-users.md) process in Business Central. This process adds cross-tenant users as Microsoft Azure Active Directory (Azure AD) business-to-business (B2B) guest users. From 5add2bcac60489a0ee28262222bf9f9090fc4880 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 12:56:06 +0200 Subject: [PATCH 121/950] fix --- .../administration/telemetry-extension-key-vault-trace.md | 4 ++-- dev-itpro/developer/devenv-app-key-vault-overview.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-itpro/administration/telemetry-extension-key-vault-trace.md b/dev-itpro/administration/telemetry-extension-key-vault-trace.md index 2b0fc3ed03..fd439affbb 100644 --- a/dev-itpro/administration/telemetry-extension-key-vault-trace.md +++ b/dev-itpro/administration/telemetry-extension-key-vault-trace.md @@ -15,7 +15,7 @@ ms.author: jswymer **INTRODUCED IN:** Business Central 2020 release wave 2 -App key vault telemetry gathers information about the acquisition of secrets in Azure Key Vaults by extensions at runtime. Secrets are a kind of credential used for authenticating an extension. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](devenv-app-key-vault-overview.md). +App key vault telemetry gathers information about the acquisition of secrets in Azure Key Vaults by extensions at runtime. Secrets are a kind of credential used for authenticating an extension. For an overview of app key vaults and secrets, see [Using App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](../developer/devenv-app-key-vault-overview.md). The app key vault secret process has two operations: *initialization* and *retrieval*. The telemetry data provides information about the success or failure for each of these operations. There are various conditions that cause a failure. The failure messages provide insight into the cause of the failure, helping you identify, troubleshoot, and resolve issues. @@ -35,7 +35,7 @@ Retrieval is the second stage, and occurs after a successful initialization. In - The Azure Key Vault Client Identity settings are incorrect. For example, like the application (client) ID of the key vault reader application in Azure. - The Business Central Server lacks permission to the private key of the Azure Key Vault client certificate. -For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](devenv-app-key-vault-overview.md). +For more information about using key vault secrets with extensions, see [App Key Vaults with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Extensions](../developer/devenv-app-key-vault-overview.md). ## App Key Vault secret initialization succeeded diff --git a/dev-itpro/developer/devenv-app-key-vault-overview.md b/dev-itpro/developer/devenv-app-key-vault-overview.md index 37c3b11f38..956f4cef31 100644 --- a/dev-itpro/developer/devenv-app-key-vault-overview.md +++ b/dev-itpro/developer/devenv-app-key-vault-overview.md @@ -16,7 +16,7 @@ Some [!INCLUDE[prodshort](../developer/includes/prodshort.md)] extensions make w These web service calls are typically authenticated, which means the extension must provide a credential in the call. The credentials enable the other service to accept or reject the call. You can consider the credentials as a kind of secret to the extension. A secret shouldn't be leaked to customers, partners, or anybody else. So where can the extension get the secret from? Here is where Azure Key Vault is used. Azure Key Vault is a cloud service that works as a secure secrets store. It provides centralized storage for secrets, enabling you to control access and distribution of the secrets. -> [NOTE] +> [!NOTE] > For [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the app key vault feature is only supported for AppSource extensions. ## Getting started From 2a14d4984390425a8e0c9265d4b050d297677d6a Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Wed, 12 Aug 2020 12:58:37 +0200 Subject: [PATCH 122/950] include --- dev-itpro/powerplatform/admin-reference.md | 40 ++++----- .../application-lifecycle-management.md | 36 ++++---- dev-itpro/powerplatform/entity-modeling.md | 86 +++++++++---------- dev-itpro/powerplatform/faq.md | 40 ++++----- dev-itpro/powerplatform/overview.md | 24 +++--- .../powerplatform/power-portal-reference.md | 18 ++-- 6 files changed, 122 insertions(+), 122 deletions(-) diff --git a/dev-itpro/powerplatform/admin-reference.md b/dev-itpro/powerplatform/admin-reference.md index 114e7f4d81..8185ff5e69 100644 --- a/dev-itpro/powerplatform/admin-reference.md +++ b/dev-itpro/powerplatform/admin-reference.md @@ -1,5 +1,5 @@ --- -title: "Business Central and Common Data Service admin reference" +title: "[!INCLUDE[prodshort](../developer/includes/prodshort.md)] and Common Data Service admin reference" ms.custom: na ms.date: 08/12/2020 ms.reviewer: solsen @@ -10,33 +10,33 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Business Central and Common Data Service admin reference +# [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and Common Data Service admin reference [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires [Platform updates for version 10.0.12 of Business Central apps](../get-started/whats-new-platform-update-10-0-12.md) and service update 189 for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires [Platform updates for version 10.0.12 of [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps](../get-started/whats-new-platform-update-10-0-12.md) and service update 189 for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -This topic provides step-by-step instructions about how to set up and configure virtual entities for Business Central apps in Common Data Service. +This topic provides step-by-step instructions about how to set up and configure virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps in Common Data Service. ## Getting the solution -The Common Data Service solution for Business Central virtual entities must be installed from Microsoft AppSource virtual entity solution. For more information, see [Business Central virtual entity](https://appsource.microsoft.com/product/dynamics-crm/mscrm.finance_and_operations_virtual_entity). +The Common Data Service solution for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities must be installed from Microsoft AppSource virtual entity solution. For more information, see [[!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity](https://appsource.microsoft.com/product/dynamics-crm/mscrm.finance_and_operations_virtual_entity). Ensure the following solutions are installed in Common Data Service. These solutions must be extracted from the downloaded package. -- **Dynamics365Company** - This adds the **Company** entity, which is referenced by all Business Central entities with a PrimaryCompanyContext metadata value. +- **Dynamics365Company** - This adds the **Company** entity, which is referenced by all [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities with a PrimaryCompanyContext metadata value. -- **MicrosoftOperationsVESupport** - This provides the core support for the Business Central virtual entity feature. +- **MicrosoftOperationsVESupport** - This provides the core support for the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity feature. -- **MicrosoftOperationsERPCatalog** - This provides a list of available Business Central entities through the mserp_financeandoperationsentity virtual entity. +- **MicrosoftOperationsERPCatalog** - This provides a list of available [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities through the mserp_financeandoperationsentity virtual entity. - **MicrosoftOperationsERPVE** - This is the API-managed solution, which will contain the generated virtual entities as they are made visible. ## Authentication and authorization -After the solutions are imported in the Common Data Service environment, both environments must be set up to connect to each other. Common Data Service will call Business Central using Service-to-Service (S2S) authentication, based on an Azure Active Directory (AAD) application. This new AAD application represents the single instance of the Common Data Service environment. If you have multiple pairs of Common Data Service and Business Central environments, separate AAD applications for each pair must be created to ensure connections are established between the correct pair of Business Central and Common Data Service environments. The following procedure shows the creation of the AAD application. +After the solutions are imported in the Common Data Service environment, both environments must be set up to connect to each other. Common Data Service will call [!INCLUDE[prodshort](../developer/includes/prodshort.md)] using Service-to-Service (S2S) authentication, based on an Azure Active Directory (AAD) application. This new AAD application represents the single instance of the Common Data Service environment. If you have multiple pairs of Common Data Service and [!INCLUDE[prodshort](../developer/includes/prodshort.md)] environments, separate AAD applications for each pair must be created to ensure connections are established between the correct pair of [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and Common Data Service environments. The following procedure shows the creation of the AAD application. > [!IMPORTANT] -> The AAD application must be created on the same tenant as Business Central. +> The AAD application must be created on the same tenant as [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. 1. Go to **\> Azure Active Directory \> App registrations**. @@ -62,11 +62,11 @@ After the solutions are imported in the Common Data Service environment, both en - Select **Save**. A key will be created and displayed. Copy this value for later use. -The AAD application created above will be used by Common Data Service to call Business Central apps. As such, it must be trusted by Business Central and associated with a user account with the appropriate rights in Business Central. A special service user must be created in Business Central with rights *only* to the virtual entity functionality, and no other rights. After completing this step, any application with the secret of the AAD application create above will be able to call this Business Central environment and access the virtual entity functionality. +The AAD application created above will be used by Common Data Service to call [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. As such, it must be trusted by [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and associated with a user account with the appropriate rights in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. A special service user must be created in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] with rights *only* to the virtual entity functionality, and no other rights. After completing this step, any application with the secret of the AAD application create above will be able to call this [!INCLUDE[prodshort](../developer/includes/prodshort.md)] environment and access the virtual entity functionality. -The next steps walk through this process in Business Central apps. +The next steps walk through this process in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. -1. In Business Central, go to **System Administration \> Users \> Users**. +1. In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], go to **System Administration \> Users \> Users**. 2. Select **New** to add a new user. Enter the following information: @@ -92,15 +92,15 @@ The next steps walk through this process in Business Central apps. - **User ID** - The user ID created above. -The next step in the process is to provide Common Data Service with the Business Central instance to connect to. The following steps walk through this part of the process. +The next step in the process is to provide Common Data Service with the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance to connect to. The following steps walk through this part of the process. 1. In Common Data Service, go to **Advanced Settings \> Administration \> Virtual Entity Data Sources**. -2. Select the data source named “Business Central”. +2. Select the data source named “[!INCLUDE[prodshort](../developer/includes/prodshort.md)]”. 3. Fill in the information from the steps above. - - **Target URL** - The URL at which you can access Business Central. + - **Target URL** - The URL at which you can access [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. - **OAuth URL** - https://login.windows.net/ @@ -110,17 +110,17 @@ The next step in the process is to provide Common Data Service with the Business - **AAD Application Secret** - The secret generated above. - - **AAD Resource** - Enter 00000015-0000-0000-c000-000000000000 (this is the AAD application representing Business Central, and should always be this same value). + - **AAD Resource** - Enter 00000015-0000-0000-c000-000000000000 (this is the AAD application representing [!INCLUDE[prodshort](../developer/includes/prodshort.md)], and should always be this same value). 4. Save the changes. ## Enabling virtual entities -Due to the large number of OData enabled entities available in Business Central, by default, the entities are not available as virtual entities in Common Data Service. The following steps allow for enabling entities to be virtual, as needed. +Due to the large number of OData enabled entities available in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], by default, the entities are not available as virtual entities in Common Data Service. The following steps allow for enabling entities to be virtual, as needed. 1. In Common Data Service, go to **Advanced find**. -2. Look for “Available Business Central Entities” and select **Results**. +2. Look for “Available [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Entities” and select **Results**. ![Catalog](../media/fovecatalog.png) @@ -132,7 +132,7 @@ Due to the large number of OData enabled entities available in Business Central, ## Refreshing virtual entity metadata -The virtual entity metadata can be force-refreshed when it is expected for the entity metadata in Business Central to have changed. This can be done by setting **Refresh** to **Yes** and saving. This will sync the latest entity definition from Business Central to Common Data Service and update the virtual entity. +The virtual entity metadata can be force-refreshed when it is expected for the entity metadata in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to have changed. This can be done by setting **Refresh** to **Yes** and saving. This will sync the latest entity definition from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to Common Data Service and update the virtual entity. Referencing virtual entities ---------------------------- diff --git a/dev-itpro/powerplatform/application-lifecycle-management.md b/dev-itpro/powerplatform/application-lifecycle-management.md index 9f30c41010..7d1e6f6cd8 100644 --- a/dev-itpro/powerplatform/application-lifecycle-management.md +++ b/dev-itpro/powerplatform/application-lifecycle-management.md @@ -15,46 +15,46 @@ author: solsen [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -The application lifecycle for an end-to-end solution using Business Central virtual entities will encompass both Business Central as well as Common Data Service. This topic explains this in detail. +The application lifecycle for an end-to-end solution using [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities will encompass both [!INCLUDE[prodshort](../developer/includes/prodshort.md)] as well as Common Data Service. This topic explains this in detail. ## Solution management -Virtual entities for Business Central don't exist in Common Data Service until they are created. Virtual entities must be created inside a solution. The MicrosoftOperationsERPVE solution is used for this purpose. This solution will contain all the virtual entities that are created from an instance of Business Central. +Virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] don't exist in Common Data Service until they are created. Virtual entities must be created inside a solution. The MicrosoftOperationsERPVE solution is used for this purpose. This solution will contain all the virtual entities that are created from an instance of [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. MicrosoftOperationsERPVE is a [managed solution](https://docs.microsoft.com/powerapps/developer/common-data-service/introduction-solutions). By definition, a managed solution can't be modified after it has been generated. However, MicrosoftOperationsERPVE is a managed solution that grants privileges to update the components (that is, virtual entities) that are inside it. Therefore, new virtual entities can be added to the solution as they are created, and existing virtual entities can be updated as required. Nevertheless, the privileges to modify the managed solution are available only to the platform itself. Users can't make changes directly to the solution. -Because MicrosoftOperationsERPVE is a managed solution, solutions from customers, partners, and independent software vendors (ISVs) can take a dependency on it. This capability allows for consistent application lifecycle management (ALM) for solutions that use and depend on the virtual entities for Business Central. +Because MicrosoftOperationsERPVE is a managed solution, solutions from customers, partners, and independent software vendors (ISVs) can take a dependency on it. This capability allows for consistent application lifecycle management (ALM) for solutions that use and depend on the virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. -When a solution that depends on MicrosoftOperationsERPVE is exported, placeholders for the virtual entities that are used in the solution are added in the exported solution. When that solution is imported into another Common Data Service environment, the import process also generates the dependent Business Central virtual entities in the MicrosoftOperationsERPVE solution for the Business Central instance that is connected to the Common Data Service environment. Therefore, MicrosoftOperationsERPVE must already exist before a solution that depends on it is imported. Otherwise, an error message is shown. Additionally, if a dependent entity isn't available in the Business Central instance, the virtual entity for that entity won't be generated. Virtual entities are generated only for entities that are available. +When a solution that depends on MicrosoftOperationsERPVE is exported, placeholders for the virtual entities that are used in the solution are added in the exported solution. When that solution is imported into another Common Data Service environment, the import process also generates the dependent [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities in the MicrosoftOperationsERPVE solution for the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance that is connected to the Common Data Service environment. Therefore, MicrosoftOperationsERPVE must already exist before a solution that depends on it is imported. Otherwise, an error message is shown. Additionally, if a dependent entity isn't available in the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance, the virtual entity for that entity won't be generated. Virtual entities are generated only for entities that are available. -The following list describes other solutions that Business Central virtual entities require to work, and that must be available in the Common Data Service environment: +The following list describes other solutions that [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities require to work, and that must be available in the Common Data Service environment: -- **MicrosoftOperationsERPCatalog** – This solution provides a catalog of the available entities in a Business Central instance. It also provides the connection that is used to set up a configuration. For more information, see the later sections of this topic. -- **MicrosoftOperationsVESupport** – This solution provides the virtual entity provider for Business Central apps. The provider can communicate with Business Central apps and Common Data Service. For more information, see the next section. -- **Dynamics365Company** – This solution adds the Company entity, which is referenced by all Business Central entities that have a **PrimaryCompanyContext** metadata value. +- **MicrosoftOperationsERPCatalog** – This solution provides a catalog of the available entities in a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance. It also provides the connection that is used to set up a configuration. For more information, see the later sections of this topic. +- **MicrosoftOperationsVESupport** – This solution provides the virtual entity provider for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. The provider can communicate with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps and Common Data Service. For more information, see the next section. +- **Dynamics365Company** – This solution adds the Company entity, which is referenced by all [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities that have a **PrimaryCompanyContext** metadata value. -All these solutions must be present in an environment. Otherwise, virtual entities won't work with Business Central apps. These solutions are packaged together to allow for easier portability across environments. +All these solutions must be present in an environment. Otherwise, virtual entities won't work with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. These solutions are packaged together to allow for easier portability across environments. ## Managing entities from multiple environments -The MicrosoftOperationsVESupport solution consists of the **msdyn\_financeandoperationsvirtualentity** entity. This entity represents the virtual entity data source for Business Central that captures connection setup information. Each record in this entity represents a connection to a Business Central instance. +The MicrosoftOperationsVESupport solution consists of the **msdyn\_financeandoperationsvirtualentity** entity. This entity represents the virtual entity data source for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] that captures connection setup information. Each record in this entity represents a connection to a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance. -A catalog is used to list all the entities in a Business Central instance that are available for virtualization in Common Data Service (in other words, all the entities in Business Central that are enabled for Open Data Protocol \[OData\]). The catalog is part of the default MicrosoftOperationsERPCatalog solution and is applicable to a Business Central instance. +A catalog is used to list all the entities in a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance that are available for virtualization in Common Data Service (in other words, all the entities in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] that are enabled for Open Data Protocol \[OData\]). The catalog is part of the default MicrosoftOperationsERPCatalog solution and is applicable to a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance. -Note that each Common Data Service environment must point to only one Business Central instance at any time, and each Business Central environment must point to only one Common Data Service environment. Therefore, there should be only one record in the **msdyn\_financeandoperationsvirtualentity** entity. +Note that each Common Data Service environment must point to only one [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance at any time, and each [!INCLUDE[prodshort](../developer/includes/prodshort.md)] environment must point to only one Common Data Service environment. Therefore, there should be only one record in the **msdyn\_financeandoperationsvirtualentity** entity. -The **mserp\_financeandoperationsentity** entity that represents the catalog can be queried to list the entities in a Business Central instance. Because this entity is a virtual entity, the catalog is never persisted in Common Data Service. +The **mserp\_financeandoperationsentity** entity that represents the catalog can be queried to list the entities in a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance. Because this entity is a virtual entity, the catalog is never persisted in Common Data Service. -Notice that the name of the catalog entity has the "mserp\_" prefix. This prefix identifies the entities in the catalog as Business Central entities. The same prefix is also added to the system names of the virtual entities that are generated for Business Central in the MicrosoftOperationsERPVE solution. Therefore, the maker can distinguish Business Central virtual entities from other entities. The prefix is set in the managed solution and can't be changed. +Notice that the name of the catalog entity has the "mserp\_" prefix. This prefix identifies the entities in the catalog as [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities. The same prefix is also added to the system names of the virtual entities that are generated for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] in the MicrosoftOperationsERPVE solution. Therefore, the maker can distinguish [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities from other entities. The prefix is set in the managed solution and can't be changed. ### Managing entities from multiple ISV solutions -One or more ISV solutions will take a dependency on the MicrosoftOperationsERPVE solution to use virtual entities for Business Central. Because custom entities in Business Central use the same catalog as out-of-box entities in Business Central, the virtual entities for custom Business Central entities will also be generated in the MicrosoftOperationsERPVE solution. +One or more ISV solutions will take a dependency on the MicrosoftOperationsERPVE solution to use virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. Because custom entities in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] use the same catalog as out-of-box entities in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the virtual entities for custom [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities will also be generated in the MicrosoftOperationsERPVE solution. -The established guidelines and ALM for entity development in Business Central ensure that there are no conflicting entity names across ISV solutions. Therefore, no conflicts of this type can occur when virtual entities are generated in Common Data Service for custom Business Central entities from multiple ISV solutions. All virtual entities for Business Central entities, including custom entities, will have the "mserp\_" prefix that was mentioned earlier. +The established guidelines and ALM for entity development in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] ensure that there are no conflicting entity names across ISV solutions. Therefore, no conflicts of this type can occur when virtual entities are generated in Common Data Service for custom [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities from multiple ISV solutions. All virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities, including custom entities, will have the "mserp\_" prefix that was mentioned earlier. ### Managing a Finance and Operation instance in a Common Data Service environment for virtual entities -One Business Central instance must be linked to a Common Data Service environment for virtual entities. The connection setup information that is required is captured in a virtual entity data source for Business Central. This data source is included in the MicrosoftOperationsERPCatalog solution. +One [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance must be linked to a Common Data Service environment for virtual entities. The connection setup information that is required is captured in a virtual entity data source for [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. This data source is included in the MicrosoftOperationsERPCatalog solution. diff --git a/dev-itpro/powerplatform/entity-modeling.md b/dev-itpro/powerplatform/entity-modeling.md index b51ebe70f1..c15e48fc5c 100644 --- a/dev-itpro/powerplatform/entity-modeling.md +++ b/dev-itpro/powerplatform/entity-modeling.md @@ -15,42 +15,42 @@ author: solsen [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -> The public entity name that is exposed in Common Data Service metadata for the Business Central virtual entity uses the physical name of the Business Central entity. This could be different from the public name of the entity as exposed by the OData metadata in Business Central apps. +> The public entity name that is exposed in Common Data Service metadata for the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity uses the physical name of the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity. This could be different from the public name of the entity as exposed by the OData metadata in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. -Building an app requires capabilities to perform relational modeling between entities that are being used in the app. In the context of virtual entities, there will be scenarios where virtual entities and native entities in Common Data Service must work together to enable the desired user experience. This topic explains concepts of relational modeling that can be implemented using virtual entities for Business Central. +Building an app requires capabilities to perform relational modeling between entities that are being used in the app. In the context of virtual entities, there will be scenarios where virtual entities and native entities in Common Data Service must work together to enable the desired user experience. This topic explains concepts of relational modeling that can be implemented using virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. ## Generating virtual entities -By default, virtual entities for Business Central apps don't exist in Common Data Service. A user must query the catalog entity to view the entities that are available in the linked instance of Business Central. From the catalog, the user can select one or more entities, and then request that Common Data Service generate the virtual entities. This procedure is explained in later sections. +By default, virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps don't exist in Common Data Service. A user must query the catalog entity to view the entities that are available in the linked instance of [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. From the catalog, the user can select one or more entities, and then request that Common Data Service generate the virtual entities. This procedure is explained in later sections. ## Entity fields -When a virtual entity is generated for a Business Central entity, the system tries to create each field in the Business Central entity in the corresponding virtual entity in Common Data Service. In an ideal case, the total number of fields will be the same in both entities, unless there is a mismatch in supported data types between Business Central and Common Data Service. For data types that are supported, the field properties in Common Data Service are set based on the properties in Business Central. +When a virtual entity is generated for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity, the system tries to create each field in the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity in the corresponding virtual entity in Common Data Service. In an ideal case, the total number of fields will be the same in both entities, unless there is a mismatch in supported data types between [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and Common Data Service. For data types that are supported, the field properties in Common Data Service are set based on the properties in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. This rest of this section describes supported and unsupported data types. For more information about fields in Common Data Service, see [Fields overview](https://docs.microsoft.com/powerapps/maker/common-data-service/fields-overview). -| Data type in Business Central | Modeled data type in Common Data Service | +| Data type in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] | Modeled data type in Common Data Service | |-------------------------------------|------------------------------------------| | Real | Decimal

For information about the possible mismatch, see the next table.

| | Long | Decimal, where the precision equals 0 (zero) | | Int | Integer | | String (non-memo), String (memo) | String – single line of text, String – multiple lines of text | -| UtcDateTime | DateTime (DateTimeFormat.DateAndTime, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Business Central is surfaced as a null value in Common Data Service. | -| Date | DateTime - (DateTimeFormat.DateOnly, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in Business Central is surfaced as an empty value in Common Data Service. | -| Enum | Picklist

Business Central enumerations (enums) are generated as global OptionSets in Common Data Service. Matching between the systems is done by using the **External Name** property of values. Enum integer values in Common Data Service aren't guaranteed to be stable between the systems. Therefore, you should not rely on them, especially in the case of extensible enums in Business Central, because these enums don't have a stable ID either. OptionSet metadata is updated when an entity that uses the OptionSet is updated. | +| UtcDateTime | DateTime (DateTimeFormat.DateAndTime, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is surfaced as a null value in Common Data Service. | +| Date | DateTime - (DateTimeFormat.DateOnly, DateTimeBehavior.TimeZoneIndependent)

An empty date (January 1, 1900) in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is surfaced as an empty value in Common Data Service. | +| Enum | Picklist

[!INCLUDE[prodshort](../developer/includes/prodshort.md)] enumerations (enums) are generated as global OptionSets in Common Data Service. Matching between the systems is done by using the **External Name** property of values. Enum integer values in Common Data Service aren't guaranteed to be stable between the systems. Therefore, you should not rely on them, especially in the case of extensible enums in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], because these enums don't have a stable ID either. OptionSet metadata is updated when an entity that uses the OptionSet is updated. | -Fields of the *real* and *long* data types in Business Central are modeled as the *decimal* data type in Common Data Service. Because of the mismatch in precision and scale between the two data types, the following behavior must be considered. +Fields of the *real* and *long* data types in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] are modeled as the *decimal* data type in Common Data Service. Because of the mismatch in precision and scale between the two data types, the following behavior must be considered. | Use case | Resulting behavior | |----------------------------------------------|--------------------| | Common Data Service has higher precision. | This use case should never occur unless the metadata is out of sync. | -| Business Central has higher precision. | During a read operation, the value is rounded to the closest precision value in Common Data Service. If the value is edited in Common Data Service, it's rounded to the closest precision value in Business Central. During a write operation, the value that is specified in Common Data Service is written, because Business Central supports higher precision. | +| [!INCLUDE[prodshort](../developer/includes/prodshort.md)] has higher precision. | During a read operation, the value is rounded to the closest precision value in Common Data Service. If the value is edited in Common Data Service, it's rounded to the closest precision value in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. During a write operation, the value that is specified in Common Data Service is written, because [!INCLUDE[prodshort](../developer/includes/prodshort.md)] supports higher precision. | | Common Data Service has higher scale. | Not applicable | -| Business Central has higher scale. | Common Data Service shows the Business Central value, even if it exceeds 100 billion. However, there will be a loss of precision. For example, 987,654,100,000,000,000 is shown in Common Data Service as "987,654,099,999,999,900". If the value of this field is edited in Common Data Service, Common Data Service validation throws an error that the value exceeds the maximum value before that value is sent to Business Central. | +| [!INCLUDE[prodshort](../developer/includes/prodshort.md)] has higher scale. | Common Data Service shows the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] value, even if it exceeds 100 billion. However, there will be a loss of precision. For example, 987,654,100,000,000,000 is shown in Common Data Service as "987,654,099,999,999,900". If the value of this field is edited in Common Data Service, Common Data Service validation throws an error that the value exceeds the maximum value before that value is sent to [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. | -The following data types in Business Central aren't supported in Common Data Service. Fields of these data types in Business Central entities won't be made available in the corresponding virtual entities in Common Data Service. If fields of these data types are used as parameters in Open Data Protocol (OData) actions, those actions won't be available for use in the corresponding virtual entities. For more information about OData actions, see the [OData actions](#odata-actions) section later in this topic. +The following data types in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] aren't supported in Common Data Service. Fields of these data types in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities won't be made available in the corresponding virtual entities in Common Data Service. If fields of these data types are used as parameters in Open Data Protocol (OData) actions, those actions won't be available for use in the corresponding virtual entities. For more information about OData actions, see the [OData actions](#odata-actions) section later in this topic. - AnyType - BLOB @@ -63,15 +63,15 @@ The following data types in Business Central aren't supported in Common Data Ser - VarArg - Void (Void return types on OData actions are supported.) -Data type that are supported in Common Data Service but not in Business Central aren't supported in virtual entities for Business Central. +Data type that are supported in Common Data Service but not in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] aren't supported in virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. ## Entity key/primary key -In Business Central, entities can have one or more fields of various data types as the entity key. An entity key uniquely identifies a record in a Business Central entity. Additionally, a record in an entity can be uniquely identified by a record ID primary key of the Int64 type. +In [!INCLUDE[prodshort](../developer/includes/prodshort.md)], entities can have one or more fields of various data types as the entity key. An entity key uniquely identifies a record in a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity. Additionally, a record in an entity can be uniquely identified by a record ID primary key of the Int64 type. In Common Data Service, the primary key is always a globally unique identifier (GUID). The GUID-based primary key enables a record in an entity in Common Data Service to be uniquely identified. -To bridge the implementation gap between Business Central and Common Data Service, the primary key of a virtual entity for Business Central is a GUID (to comply with Common Data Service). This GUID consists of the data entity ID in the first 4 bytes, and the record ID of the root data source in the entity as the last 8 bytes. This design satisfies Common Data Service's requirement that a GUID be used as the entity key. It also enables the table ID and record ID to be used to uniquely identify the entity record in Business Central. +To bridge the implementation gap between [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and Common Data Service, the primary key of a virtual entity for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is a GUID (to comply with Common Data Service). This GUID consists of the data entity ID in the first 4 bytes, and the record ID of the root data source in the entity as the last 8 bytes. This design satisfies Common Data Service's requirement that a GUID be used as the entity key. It also enables the table ID and record ID to be used to uniquely identify the entity record in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. ## Primary field @@ -81,31 +81,31 @@ In Common Data Service, each entity must have a primary field. This field must b - The quick view form for an entity includes the primary field. - A lookup to another entity is added to a page and shows the data from the primary field. -Based on this use of the primary field in Common Data Service, the primary field for a virtual entity for Business Central is designed to use the entity key of the corresponding entity in Business Central. +Based on this use of the primary field in Common Data Service, the primary field for a virtual entity for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is designed to use the entity key of the corresponding entity in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. -Because the primary field in Common Data Service is expected to have only one field of the string type, whereas the entity key in Business Central can have multiple fields of various data types, the entity key fields are converted to strings. The strings are concatenated and separated by a pipe (\|), to a maximum length of 255 characters. Any value that exceeds 255 is truncated. This virtual entity field that represents the primary field is named **mserp\_primaryfield**. +Because the primary field in Common Data Service is expected to have only one field of the string type, whereas the entity key in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] can have multiple fields of various data types, the entity key fields are converted to strings. The strings are concatenated and separated by a pipe (\|), to a maximum length of 255 characters. Any value that exceeds 255 is truncated. This virtual entity field that represents the primary field is named **mserp\_primaryfield**. ## Relations > [!IMPORTANT] > A write transaction that spans a virtual entity and a native entity is not supported. We do not recommend using this form of transaction, as there is no way to ensure consistency. -Relations in Business Central entities are modeled as one-to-many (1:n) or many-to-one (n:1) relations. These relations are modeled as relationships in the virtual entity in Common Data Service. Note that many-to-many (n:n) relations aren't supported in Business Central. +Relations in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities are modeled as one-to-many (1:n) or many-to-one (n:1) relations. These relations are modeled as relationships in the virtual entity in Common Data Service. Note that many-to-many (n:n) relations aren't supported in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. -For example, in Business Central, if Entity A has a foreign key to Entity B, this relation will be modeled as an n:1 relationship in virtual entity Entity A in Common Data Service. The schema name of this relationship in Common Data Service uses the naming convention **mserp\_FK\_\\_\**. This naming convention has a maximum string length of 120 characters. Any relation where the schema name will produce a name that exceeds 120 characters won't be generated in the virtual entity in Common Data Service. +For example, in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], if Entity A has a foreign key to Entity B, this relation will be modeled as an n:1 relationship in virtual entity Entity A in Common Data Service. The schema name of this relationship in Common Data Service uses the naming convention **mserp\_FK\_\\_\**. This naming convention has a maximum string length of 120 characters. Any relation where the schema name will produce a name that exceeds 120 characters won't be generated in the virtual entity in Common Data Service. -The external name of this relationship uses the naming convention **FK\_\**. The external name is used to determine the relation in Business Central when the query that is sent to Business Central is built. +The external name of this relationship uses the naming convention **FK\_\**. The external name is used to determine the relation in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] when the query that is sent to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is built. -When a relationship is generated for a virtual entity in Common Data Service, a new field of the lookup type is also added to the source entity. In the preceding example, when the relationship is created, a new lookup field that uses the naming convention **mserp\_fk\_\\_id** is added to source entity Entity A. Because there can be several relations in an entity in Business Central, the same number of lookup fields (one per related entity) will be created in the source virtual entity. When this lookup field is added to a page or a view, it will show the primary field value from the related entity. +When a relationship is generated for a virtual entity in Common Data Service, a new field of the lookup type is also added to the source entity. In the preceding example, when the relationship is created, a new lookup field that uses the naming convention **mserp\_fk\_\\_id** is added to source entity Entity A. Because there can be several relations in an entity in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], the same number of lookup fields (one per related entity) will be created in the source virtual entity. When this lookup field is added to a page or a view, it will show the primary field value from the related entity. -A relationship in the virtual entity in Common Data Service will be generated only if the related entity in the relation already exists as a virtual entity in Common Data Service. In the preceding example, if Entity B doesn't exist as a virtual entity in Common Data Service, the relation to Entity B won't be created in Entity A when Entity A is generated as a virtual entity. This relation will be added to Entity A only when Entity B is generated as a virtual entity. Therefore, when a virtual entity is generated for Business Central, validations are done to ensure that only relationships that can be complete and functional are generated in the virtual entity that is being generated. +A relationship in the virtual entity in Common Data Service will be generated only if the related entity in the relation already exists as a virtual entity in Common Data Service. In the preceding example, if Entity B doesn't exist as a virtual entity in Common Data Service, the relation to Entity B won't be created in Entity A when Entity A is generated as a virtual entity. This relation will be added to Entity A only when Entity B is generated as a virtual entity. Therefore, when a virtual entity is generated for [!INCLUDE[prodshort](../developer/includes/prodshort.md)], validations are done to ensure that only relationships that can be complete and functional are generated in the virtual entity that is being generated. -In summary, a relationship to another Business Central virtual entity might not exist in the virtual entity for either of the following reasons: +In summary, a relationship to another [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity might not exist in the virtual entity for either of the following reasons: -- The Business Central entity that is participating in the relationship doesn't exist as a virtual entity. +- The [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity that is participating in the relationship doesn't exist as a virtual entity. - The length of the name of the relationship exceeds 120 characters. -Note that if an error is encountered when any part of a Business Central virtual entity is generated in Common Data Service, the virtual entity won't be created at all. If relationships don't exist for either of the preceding reasons, the situation isn't considered an error. +Note that if an error is encountered when any part of a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity is generated in Common Data Service, the virtual entity won't be created at all. If relationships don't exist for either of the preceding reasons, the situation isn't considered an error. ### Native entity–to–native entity relationships @@ -113,17 +113,17 @@ Native entity–to–native entity relationships are the standard Common Data Se ### Virtual entity–to–virtual entity relationships -The relationships between two Business Central virtual entities are driven by the relation metadata in the Business Central entities. As was explained earlier, these relations are generated as relationships in Common Data Service when the virtual entity is generated. As in the behavior for native entities in Common Data Service, these relationships use the GUID to identify the unique record of the entity in Business Central. Semantically, the GUID on the Business Central virtual entity behaves like the GUID on the native Common Data Service entity. For information about the implementation of the GUID in Business Central virtual entities, see the [Entity key/primary key](entity-modeling.md#entity-keyprimary-key) section earlier in this topic. +The relationships between two [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities are driven by the relation metadata in the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities. As was explained earlier, these relations are generated as relationships in Common Data Service when the virtual entity is generated. As in the behavior for native entities in Common Data Service, these relationships use the GUID to identify the unique record of the entity in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. Semantically, the GUID on the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity behaves like the GUID on the native Common Data Service entity. For information about the implementation of the GUID in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities, see the [Entity key/primary key](entity-modeling.md#entity-keyprimary-key) section earlier in this topic. In the preceding example, the GUID of the related entity is the entity key of Entity B and will be used to build queries to identify a record in Finance and Operation. The relation that Entity A has to Entity B will be used. -Therefore, in effect, the entity name is the only information that is used in a relation that comes from Business Central. The entity name gives access to the primary field in the related entity, so that it can be shown in the lookup. It also gives access to the GUID of the related entity, so that it can be used in other queries, as was explained earlier. The actual field that the relation is built on in the Business Central entity isn't used at all. +Therefore, in effect, the entity name is the only information that is used in a relation that comes from [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. The entity name gives access to the primary field in the related entity, so that it can be shown in the lookup. It also gives access to the GUID of the related entity, so that it can be used in other queries, as was explained earlier. The actual field that the relation is built on in the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity isn't used at all. ### Virtual entity–to–native entity relationship -As was explained earlier, the GUID is the only information that is used to uniquely identify a record in a native Common Data Service entity (including in native entity–to–native entity relationships) or in a Business Central virtual entity (including in virtual entity–to–virtual entity relationships). However, consider an example where you want to show sales orders from Business Central for Account A in Common Data Service. The query that is sent to Business Central for this relationship will have a WHERE clause on the GUID of the entity key of the native accounts entity in Common Data Service, because the sales orders must be filtered for a specific account in Common Data Service. However, because Business Central doesn't have any information about the GUID of the entity in Common Data Service, the query won't return any sales orders. The query will be successful only if the WHERE clause has conditions that are based on the fields that Business Central understands. +As was explained earlier, the GUID is the only information that is used to uniquely identify a record in a native Common Data Service entity (including in native entity–to–native entity relationships) or in a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity (including in virtual entity–to–virtual entity relationships). However, consider an example where you want to show sales orders from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] for Account A in Common Data Service. The query that is sent to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] for this relationship will have a WHERE clause on the GUID of the entity key of the native accounts entity in Common Data Service, because the sales orders must be filtered for a specific account in Common Data Service. However, because [!INCLUDE[prodshort](../developer/includes/prodshort.md)] doesn't have any information about the GUID of the entity in Common Data Service, the query won't return any sales orders. The query will be successful only if the WHERE clause has conditions that are based on the fields that [!INCLUDE[prodshort](../developer/includes/prodshort.md)] understands. -Therefore, how can the GUID of the accounts entity in Common Data Service be replaced with fields that are in Business Central, in such a way that the query that is sent to Business Central will return the correct list of sales orders? +Therefore, how can the GUID of the accounts entity in Common Data Service be replaced with fields that are in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], in such a way that the query that is sent to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] will return the correct list of sales orders? To solve this issue and enable a rich set of scenarios that allows for virtual entity–to–native entity relationships, relationships can be added to this type of entity. The relation will appear as a relationship when the virtual entity is synced. @@ -151,31 +151,31 @@ The field mapping indicates which field on the virtual entity maps to the field ``` The next step is to generate or refresh the virtual entity to get the new relationship. Note that relationships between a virtual entity and a native entity cannot be updated in Common Data Service once it is created. The only way to make an update is to physically remove the relationship, refresh the entity, and then physically re-add the relationship in order to resolve the issue. -This relationship looks like a typical GUID-based relationship, but has extra metadata to translate query filters on the relationship into restrictions on the backing fields. The query that is now generated will have a WHERE clause that is based on the fields that Business Central apps recognize. That query will then return the filtered list of sales orders, as expected. +This relationship looks like a typical GUID-based relationship, but has extra metadata to translate query filters on the relationship into restrictions on the backing fields. The query that is now generated will have a WHERE clause that is based on the fields that [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps recognize. That query will then return the filtered list of sales orders, as expected. ### Native entity–to–virtual entity relationships -Native entity–to–virtual entity relationships works much like native entity–to–native entity relationships. Users associate native records with virtual records in Business Central, and the GUID of the virtual entity is saved on the native entity record. As was explained earlier, the entities that participate in a relationship will have the GUID field of the related entity on them. Therefore, when a quotation in Common Data Service is associated with a customer in a Business Central virtual entity, the GUID of the customer virtual entity will be saved in the quotation entity. This behavior enables records to be retrieved as expected, by using standard Common Data Service functionality. +Native entity–to–virtual entity relationships works much like native entity–to–native entity relationships. Users associate native records with virtual records in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], and the GUID of the virtual entity is saved on the native entity record. As was explained earlier, the entities that participate in a relationship will have the GUID field of the related entity on them. Therefore, when a quotation in Common Data Service is associated with a customer in a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entity, the GUID of the customer virtual entity will be saved in the quotation entity. This behavior enables records to be retrieved as expected, by using standard Common Data Service functionality. ## Enums -Enums in Business Central are modeled as OptionSets in Common Data Service. When a virtual entity for Business Central is generated, the required enums are generated as OptionSets. If an OptionSet already exists, it's used instead. +Enums in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] are modeled as OptionSets in Common Data Service. When a virtual entity for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is generated, the required enums are generated as OptionSets. If an OptionSet already exists, it's used instead. ## Company -An entity in Business Central can be bound to a company, or it can be global. The virtual entity for a Business Central entity that is bound to a company will have a relationship to the cdm\_company entity in Common Data Service. The cdm\_company entity is a native entity in Common Data Service and is part of the Dynamics365Company solution. As always, when a relationship is created, a lookup field is also created in the virtual entity for the related entity (cdm\_company in this case). This lookup field is named **Company**, and it must be used to provide an optimal user experience where users can select a value in a list or go to the details of the related record. A field that is named **Company Code** is also added in the virtual entity. The value is a four-character string. This field must be used in programming. +An entity in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] can be bound to a company, or it can be global. The virtual entity for a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity that is bound to a company will have a relationship to the cdm\_company entity in Common Data Service. The cdm\_company entity is a native entity in Common Data Service and is part of the Dynamics365Company solution. As always, when a relationship is created, a lookup field is also created in the virtual entity for the related entity (cdm\_company in this case). This lookup field is named **Company**, and it must be used to provide an optimal user experience where users can select a value in a list or go to the details of the related record. A field that is named **Company Code** is also added in the virtual entity. The value is a four-character string. This field must be used in programming. ## Attachments -Attachments in Business Central entities are supported on a per-entity basis. For example, an invoice header entity will implement an invoice-related attachments entity to [enable attachments via entities](../../fin-ops/organization-administration/configure-document-management.md#how-can-attachments-be-extracted-from-the-system). +Attachments in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities are supported on a per-entity basis. For example, an invoice header entity will implement an invoice-related attachments entity to [enable attachments via entities](../../fin-ops/organization-administration/configure-document-management.md#how-can-attachments-be-extracted-from-the-system). -Entities of this type will have relations with the corresponding attachments entity in Business Central. Therefore, they will follow the same pattern as the other relations that were discussed earlier. In other words, Business Central entities that have implemented attachments functionality will also make attachments available by using virtual entities. Business Central entities that don't support attachments also won't support attachments when they are virtualized in Common Data Service. +Entities of this type will have relations with the corresponding attachments entity in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. Therefore, they will follow the same pattern as the other relations that were discussed earlier. In other words, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities that have implemented attachments functionality will also make attachments available by using virtual entities. [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities that don't support attachments also won't support attachments when they are virtualized in Common Data Service. -Note that Business Central virtual entities support only the reading of attachments. They don't currently support the creation, update, or deletion of attachments by using virtual entities. +Note that [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities support only the reading of attachments. They don't currently support the creation, update, or deletion of attachments by using virtual entities. ## OData actions -OData actions in the Business Central entities are made available as custom actions in Common Data Service. For more information about custom actions and what they enable in Common Data Service, see [Custom actions](https://docs.microsoft.com/powerapps/developer/common-data-service/custom-actions). +OData actions in the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities are made available as custom actions in Common Data Service. For more information about custom actions and what they enable in Common Data Service, see [Custom actions](https://docs.microsoft.com/powerapps/developer/common-data-service/custom-actions). Input and output parameters of the following types are supported. If an input or output parameter is of a different type, the OData action doesn't appear as the SDK message in Common Data Service. @@ -185,7 +185,7 @@ Input and output parameters of the following types are supported. If an input or - Boolean - Date/Datetime -Here are some examples of OData actions that are supported in Business Central entities, but that aren't supported in the corresponding virtual entities in Common Data Service: +Here are some examples of OData actions that are supported in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities, but that aren't supported in the corresponding virtual entities in Common Data Service: - RetailStoreTenderTypeTable.queryDistinctTenderTypeIdAndName (a collection of RetailStoreTenderTypeTable entity) - DocumentRoutingClientApp.syncPrinters (DocumentRoutingClientApp entity) @@ -194,14 +194,14 @@ Here are some examples of OData actions that are supported in Business Central e ## Labels and localization -Labels that are defined on metadata, such as entity names and field names in Business Central, are retrieved when virtual entities are generated in Common Data Service. The labels are retrieved by passing the list of language locales that are installed in Common Data Service. Business Central returns each label as a list of locale/value sets that are then used to construct a label instance in Common Data Service. Only the language packs that exist at the time of entity generation or update are included. Additionally, only labels that Business Central has provided a translation for are included. Any missing translations revert to the label ID, such as **\@SYS:DataEntity**. After a new language pack is installed in Common Data Service, existing entities must be updated to pick up the new label information, if labels in that language exist in Business Central. +Labels that are defined on metadata, such as entity names and field names in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], are retrieved when virtual entities are generated in Common Data Service. The labels are retrieved by passing the list of language locales that are installed in Common Data Service. [!INCLUDE[prodshort](../developer/includes/prodshort.md)] returns each label as a list of locale/value sets that are then used to construct a label instance in Common Data Service. Only the language packs that exist at the time of entity generation or update are included. Additionally, only labels that [!INCLUDE[prodshort](../developer/includes/prodshort.md)] has provided a translation for are included. Any missing translations revert to the label ID, such as **\@SYS:DataEntity**. After a new language pack is installed in Common Data Service, existing entities must be updated to pick up the new label information, if labels in that language exist in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. -Any runtime labels are returned in the language of the current user context. In other words, they are returned in the language that is specified on that user's UserInfo record in Business Central. This behavior also applies to error messages. +Any runtime labels are returned in the language of the current user context. In other words, they are returned in the language that is specified on that user's UserInfo record in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. This behavior also applies to error messages. ## Error handling -Business Central create, read, update, and delete (CRUD) business logic on entities and backing tables is run when it's called through the virtual entity in Common Data Service. If any exception is thrown on the Business Central side, the last message in the error log is returned to Common Data Service and is thrown as an InvalidPluginExecutionException exception that contains the message from Business Central. Because the Business Central code runs in the context of the user, the language of the error message is based on the language that is specified on the UserInfo record in Business Central. If any messages that are written to the info log in Business Central don't result in an exception, they aren't shown in Common Data Service. +[!INCLUDE[prodshort](../developer/includes/prodshort.md)] create, read, update, and delete (CRUD) business logic on entities and backing tables is run when it's called through the virtual entity in Common Data Service. If any exception is thrown on the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] side, the last message in the error log is returned to Common Data Service and is thrown as an InvalidPluginExecutionException exception that contains the message from [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. Because the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] code runs in the context of the user, the language of the error message is based on the language that is specified on the UserInfo record in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. If any messages that are written to the info log in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] don't result in an exception, they aren't shown in Common Data Service. ## Calculated/unmapped fields -Calculated and unmapped fields in Business Central entities are also available in the corresponding virtual entities in Common Data Service. +Calculated and unmapped fields in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities are also available in the corresponding virtual entities in Common Data Service. diff --git a/dev-itpro/powerplatform/faq.md b/dev-itpro/powerplatform/faq.md index 237f04437a..89ca074f45 100644 --- a/dev-itpro/powerplatform/faq.md +++ b/dev-itpro/powerplatform/faq.md @@ -1,5 +1,5 @@ --- -title: "Business Central virtual entities FAQ" +title: "[!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities FAQ" ms.custom: na ms.date: 08/12/2020 ms.reviewer: solsen @@ -10,20 +10,20 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Business Central virtual entities FAQ +# [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities FAQ [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -This topic is a collection of frequently asked questions about Business Central virtual entities. +This topic is a collection of frequently asked questions about [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities. -### Do Tier 1 Business Central environments or demo topologies work? +### Do Tier 1 [!INCLUDE[prodshort](../developer/includes/prodshort.md)] environments or demo topologies work? Yes, Tier 1 and DEVTEST and DEMO topologies should work. -### What version of Business Central do I need? +### What version of [!INCLUDE[prodshort](../developer/includes/prodshort.md)] do I need? 10.0.12 is the minimum version that is required. @@ -31,33 +31,33 @@ Yes, Tier 1 and DEVTEST and DEMO topologies should work. Yes. The virtual entities are all generated in the MicrosoftOperationsERPVE solution, which isAPI-managed In other words, the items in the solution change as you make entities visible or hidden, but the solution is still a managed solution that you can take dependency on. The standard ALM flow just takes a standard reference to a virtual entity from this solution with the **Add existing** option in the ISV solution. Missing dependency of the solution will be checked when the solution is imported and during import, if a specified virtual entity doesn't yet exist, the virtual entity is automatically made visible. -### Which entities from Business Central do users see in the catalog in Common Data Service? +### Which entities from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] do users see in the catalog in Common Data Service? Generally, users see all entities where **IsPublic** is set to **Yes**. These entities are the same entities that are currently visible in Open Data Protocol (OData). -### Do all Microsoft Power Platform users have to be users in Business Central? +### Do all Microsoft Power Platform users have to be users in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]? -Any user of Microsoft Power Platform who tries to access Business Central data through a virtual entity must also exist as a user in Business Central. Therefore, technically, not *all* users have to be users in Business Central. Only those users who access Business Central data through virtual entities must be users in Business Central. +Any user of Microsoft Power Platform who tries to access [!INCLUDE[prodshort](../developer/includes/prodshort.md)] data through a virtual entity must also exist as a user in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. Therefore, technically, not *all* users have to be users in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. Only those users who access [!INCLUDE[prodshort](../developer/includes/prodshort.md)] data through virtual entities must be users in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. ### Where do I find the catalog entity? -In the **Advanced find** window, the entity is named **Available Business Central Entities**. +In the **Advanced find** window, the entity is named **Available [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Entities**. ### Is there a way to specify a company when I perform data operations on a virtual entity? -Yes. Although the company is implicit in Business Central, it's an explicit field on each company-striped entity in Common Data Service. You can use either the **Company Code** field, where the value is a four-character string, or the **Company** field, which is a lookup to cdm\_Company. Both approaches provide the same information. +Yes. Although the company is implicit in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], it's an explicit field on each company-striped entity in Common Data Service. You can use either the **Company Code** field, where the value is a four-character string, or the **Company** field, which is a lookup to cdm\_Company. Both approaches provide the same information. ### Can I change the prefix for the virtual entities? -No. All Business Central virtual entities should be generated in the MicrosoftOperationsERPVE solution, and they should all have the "mserp\_" prefix. This prefix should not be changed. If you have a scenario where you believe the prefix has to be changed, you should share that scenario with Microsoft. +No. All [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities should be generated in the MicrosoftOperationsERPVE solution, and they should all have the "mserp\_" prefix. This prefix should not be changed. If you have a scenario where you believe the prefix has to be changed, you should share that scenario with Microsoft. ### How can I filter data in an app that is created by using Power Apps, based on the current user or any other dynamic criteria, such as today-10? You can write a pre-operation plug-in on the RetrieveMultiple message of the entity and change the criteria on the query in it. Alternatively, you can write a post-operation plug-in to filter the results before they are returned. -### Can I pin a model-driven app into Business Central? +### Can I pin a model-driven app into [!INCLUDE[prodshort](../developer/includes/prodshort.md)]? -No, it isn't currently possible to pin a model-driven app into Business Central. +No, it isn't currently possible to pin a model-driven app into [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. ### How can I show, in the same grid, data from multiple virtual entities that are joined to a physical entity record in Common Data Service? @@ -77,17 +77,17 @@ As in the previous Power Apps user interface (UI), you must redo the **Add Exist Yes. Here is the order of calls: 1. Common Data Service sends a create or update message. -2. All the existing logic on the Business Central entity and backing tables is invoked. This logic includes default value entry that might change values. +2. All the existing logic on the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity and backing tables is invoked. This logic includes default value entry that might change values. 3. Common Data Service sends another Retrieve (single) message to get the latest copy of the data, including any fields that default values were entered for. -### Can I debug Business Central when we do a create, read, update, and delete (CRUD) operation from Common Data Service? If so, which process do I have to attach? +### Can I debug [!INCLUDE[prodshort](../developer/includes/prodshort.md)] when we do a create, read, update, and delete (CRUD) operation from Common Data Service? If so, which process do I have to attach? -Yes, to debug in Business Central, open Visual Studio as an admin. Typically, Business Central apps run under w3wp.exe as a process. However, when you open Visual Studio as an admin, IISExpress.exe is automatically opened, and Business Central is hosted there. You can attach to IISExpress.exe (or to w3wp.exe if not running Visual Studio as an admin). To set breakpoints in the virtual entity code, find the **CDSVirtualEntityAdapter** and **CDSVirtualEntityController** classes. The adapter class is the first class that is called, and it only does serialization/deserialization. It then delegates to the controller class to do the actual queries. Therefore, the controller class is usually the easiest place to put breakpoints. +Yes, to debug in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], open Visual Studio as an admin. Typically, [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps run under w3wp.exe as a process. However, when you open Visual Studio as an admin, IISExpress.exe is automatically opened, and [!INCLUDE[prodshort](../developer/includes/prodshort.md)] is hosted there. You can attach to IISExpress.exe (or to w3wp.exe if not running Visual Studio as an admin). To set breakpoints in the virtual entity code, find the **CDSVirtualEntityAdapter** and **CDSVirtualEntityController** classes. The adapter class is the first class that is called, and it only does serialization/deserialization. It then delegates to the controller class to do the actual queries. Therefore, the controller class is usually the easiest place to put breakpoints. -### Does the form business logic in Business Central get called through virtual entities? +### Does the form business logic in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] get called through virtual entities? -Business Central business logic that resides on forms isn't invoked through virtual entities. Instead, you should expect the same behavior that you get through OData access to the same entities. The expectation is that an entity that is exposed to OData (that is, **IsPublic** is set to **Yes**) has appropriate protections to ensure that data can't be corrupted. If any entity lacks this protection, that situation represents a bug in the entity. If you see differences in entity behavior between OData and virtual entities, that situation represents a bug in the virtual entity feature. +[!INCLUDE[prodshort](../developer/includes/prodshort.md)] business logic that resides on forms isn't invoked through virtual entities. Instead, you should expect the same behavior that you get through OData access to the same entities. The expectation is that an entity that is exposed to OData (that is, **IsPublic** is set to **Yes**) has appropriate protections to ensure that data can't be corrupted. If any entity lacks this protection, that situation represents a bug in the entity. If you see differences in entity behavior between OData and virtual entities, that situation represents a bug in the virtual entity feature. -### If I develop a new Business Central entity and want to see it in Common Data Service, do I have to select Refresh entity list in Business Central? Do I have to do anything in Common Data Service? +### If I develop a new [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity and want to see it in Common Data Service, do I have to select Refresh entity list in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]? Do I have to do anything in Common Data Service? In theory, no, you don't have to refresh the entity list. At most, you might have to either reset Internet Information Services (IIS) or restart IIS Express, depending on where Application Object Server (AOS) is running. The fact that the list of entities is accurate is cached in SysGlobalObjectCache, which is a per-process cache. Any time that this cache doesn't indicate that the list is accurate, the list is rebuilt. The rebuild process takes about five seconds. Therefore, when you restart your AOS process (w3wp.exe or iisexpress.exe), the list will be accurate the next time that you query it from Common Data Service. Additionally, although recompilation *should* flush the SysGlobalObjectCache cache, it might not. In that case, an AOS restart will flush it. diff --git a/dev-itpro/powerplatform/overview.md b/dev-itpro/powerplatform/overview.md index 193b0b0b26..c5998ab761 100644 --- a/dev-itpro/powerplatform/overview.md +++ b/dev-itpro/powerplatform/overview.md @@ -1,5 +1,5 @@ --- -title: "Microsoft Power Platform integration with Business Central" +title: "Microsoft Power Platform integration with [!INCLUDE[prodshort](../developer/includes/prodshort.md)]" ms.custom: na ms.date: 08/12/2020 ms.reviewer: solsen @@ -10,18 +10,18 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Microsoft Power Platform integration with Business Central +# Microsoft Power Platform integration with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -Business Central is a virtual data source in Common Data Service, and enables full create, read, update, delete (CRUD) operations from Common Data Service and Microsoft Power Platform. By definition, the data for virtual entities doesn't reside in Common Data Service. Instead, it continues to reside in the application where it belongs. To enable CRUD operations on Business Central entities from Common Data Service, entities must be made available as virtual entities in Common Data Service. The allows CRUD operations to be performed, from Common Data Service and Microsoft Power Platform, on data that resides in Business Central apps. +[!INCLUDE[prodshort](../developer/includes/prodshort.md)] is a virtual data source in Common Data Service, and enables full create, read, update, delete (CRUD) operations from Common Data Service and Microsoft Power Platform. By definition, the data for virtual entities doesn't reside in Common Data Service. Instead, it continues to reside in the application where it belongs. To enable CRUD operations on [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities from Common Data Service, entities must be made available as virtual entities in Common Data Service. The allows CRUD operations to be performed, from Common Data Service and Microsoft Power Platform, on data that resides in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. ## Prerequisite reading -To understand the architecture of virtual entities for Business Central apps, you must understand how Common Data Service and virtual entities work. Therefore, the following documentation is a prerequisite: +To understand the architecture of virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps, you must understand how Common Data Service and virtual entities work. Therefore, the following documentation is a prerequisite: - [What is Common Data Service?](https://docs.microsoft.com/powerapps/maker/common-data-service/data-platform-intro) - [Entity overview](https://docs.microsoft.com/powerapps/maker/common-data-service/entity-overview) @@ -30,18 +30,18 @@ To understand the architecture of virtual entities for Business Central apps, yo - [What is Power Apps portals?](https://docs.microsoft.com/powerapps/maker/portals/overview) - [Overview of creating apps in Power Apps](https://docs.microsoft.com/powerapps/maker/) -## Virtual entities for Business Central apps +## Virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps -All Open Data Protocol (OData) entities in Business Central are available as virtual entities in Common Data Service, and therefore also in Power Platform. Makers can now build experiences in customer engagement apps with data directly from Business Central with full CRUD capability and without copying to Common Data Service. Power Apps Portals can be used to build external-facing websites that enable collaboration scenarios for business processes in Business Central. +All Open Data Protocol (OData) entities in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] are available as virtual entities in Common Data Service, and therefore also in Power Platform. Makers can now build experiences in customer engagement apps with data directly from [!INCLUDE[prodshort](../developer/includes/prodshort.md)] with full CRUD capability and without copying to Common Data Service. Power Apps Portals can be used to build external-facing websites that enable collaboration scenarios for business processes in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. ## Architecture -Virtual entities are a Common Data Service concept that is useful beyond Business Central. The following illustration shows how the Business Central provider for virtual entities is implemented. Six primary methods are implemented by the provider. The first five methods are the standard CRUD operations: **Create**, **Update**, **Delete**, **Retrieve**, and **RetrieveMultiple**. The last method, **PerformAction**, is used to call OData actions, as described later in this topic. Calls to the Business Central Virtual Entity Data Provider (shown as "VE Plugin" in the illustration) will cause a Secure Sockets Layer (SSL)/Transport Layer Security (TLS) 1.2 secure web call to the CDSVirtualEntityService web API endpoint of Business Central. This web service then converts the queries into calls to the associated physical entities in Business Central, and invokes CRUD or OData operations on those entities. Because a Business Central entity is directly invoked in all operations, any business logic on the entity or its backing tables is also invoked. +Virtual entities are a Common Data Service concept that is useful beyond [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. The following illustration shows how the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] provider for virtual entities is implemented. Six primary methods are implemented by the provider. The first five methods are the standard CRUD operations: **Create**, **Update**, **Delete**, **Retrieve**, and **RetrieveMultiple**. The last method, **PerformAction**, is used to call OData actions, as described later in this topic. Calls to the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Virtual Entity Data Provider (shown as "VE Plugin" in the illustration) will cause a Secure Sockets Layer (SSL)/Transport Layer Security (TLS) 1.2 secure web call to the CDSVirtualEntityService web API endpoint of [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. This web service then converts the queries into calls to the associated physical entities in [!INCLUDE[prodshort](../developer/includes/prodshort.md)], and invokes CRUD or OData operations on those entities. Because a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity is directly invoked in all operations, any business logic on the entity or its backing tables is also invoked. -[![Architecture of virtual entities for Business Central apps](../media/fovearchitecture.png)](../media/fovearchitecture.png) +[![Architecture of virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps](../media/fovearchitecture.png)](../media/fovearchitecture.png) -During calls, there are two points of translation from Common Data Service to Business Central apps. The first point of translation occurs in the VE Plugin, which translates concepts such as entity physical names into Business Central entity names. It also converts some well-known concepts, such as Company references. The web service call still uses the EntityCollection, Entity, and QueryExpression objects to express the operations that are performed, by using the translated entity names and concepts from the VE Plugin. Finally, the CDSVirtualEntityAdapterService web API in Business Central completes the translation from QueryExpression to QueryBuildDataSource and other internal Business Central language constructs. +During calls, there are two points of translation from Common Data Service to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. The first point of translation occurs in the VE Plugin, which translates concepts such as entity physical names into [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entity names. It also converts some well-known concepts, such as Company references. The web service call still uses the EntityCollection, Entity, and QueryExpression objects to express the operations that are performed, by using the translated entity names and concepts from the VE Plugin. Finally, the CDSVirtualEntityAdapterService web API in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] completes the translation from QueryExpression to QueryBuildDataSource and other internal [!INCLUDE[prodshort](../developer/includes/prodshort.md)] language constructs. -All calls between Common Data Service and Business Central as part of virtual entities are done as service-to-service (S2S) calls by using the Azure Active Directory (Azure AD) application that is specified in the configuration. The user of this application should have access *only* to the CDSVirtualEntityAdapterService web API and the Catalog entity, CDSVirtualEntityListEntity. These privileges are included in the out-of-box security role that is named CDSVirtualEntityApplication. During the S2S calls, Common Data Service provides the identity of the user in Common Data Service who is invoking the action. The CDSVirtualEntityAdapterService web API looks up the associated user in Business Central and runs the query in the context of that user. Therefore, the S2S call doesn't have to have explicit access to all the Business Central entities. Instead, it can rely on the privileges of the user who is invoking the action to determine data access. +All calls between Common Data Service and [!INCLUDE[prodshort](../developer/includes/prodshort.md)] as part of virtual entities are done as service-to-service (S2S) calls by using the Azure Active Directory (Azure AD) application that is specified in the configuration. The user of this application should have access *only* to the CDSVirtualEntityAdapterService web API and the Catalog entity, CDSVirtualEntityListEntity. These privileges are included in the out-of-box security role that is named CDSVirtualEntityApplication. During the S2S calls, Common Data Service provides the identity of the user in Common Data Service who is invoking the action. The CDSVirtualEntityAdapterService web API looks up the associated user in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and runs the query in the context of that user. Therefore, the S2S call doesn't have to have explicit access to all the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities. Instead, it can rely on the privileges of the user who is invoking the action to determine data access. -Power Apps Portal can also access virtual entities. Because Power Apps Portal authorization is based on contact records, a mapping between contact records and Business Central users is maintained in the msdyn\_externalportalusermapping table in Common Data Service. This table should be editable only by highly privileged users in Common Data Service, who have the rights to control the security access of portal users to Business Central virtual entities. Any Business Central user who is set up for Power Apps Portal access must have the CDSVirtualEntityAuthorizedPortalUser security role assigned, and can't have the System administrator or Security administrator role assigned. Regardless of the Power Apps Portal security setting that is applied to virtual entities, the resulting query to Business Central apps is always run as the associated Business Central user, and is subject to that user's entity and row security settings. Anonymous portal access is also supported. For information about this type of access and how it can be done, see [Power Apps Portal reference](power-portal-reference.md). +Power Apps Portal can also access virtual entities. Because Power Apps Portal authorization is based on contact records, a mapping between contact records and [!INCLUDE[prodshort](../developer/includes/prodshort.md)] users is maintained in the msdyn\_externalportalusermapping table in Common Data Service. This table should be editable only by highly privileged users in Common Data Service, who have the rights to control the security access of portal users to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities. Any [!INCLUDE[prodshort](../developer/includes/prodshort.md)] user who is set up for Power Apps Portal access must have the CDSVirtualEntityAuthorizedPortalUser security role assigned, and can't have the System administrator or Security administrator role assigned. Regardless of the Power Apps Portal security setting that is applied to virtual entities, the resulting query to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps is always run as the associated [!INCLUDE[prodshort](../developer/includes/prodshort.md)] user, and is subject to that user's entity and row security settings. Anonymous portal access is also supported. For information about this type of access and how it can be done, see [Power Apps Portal reference](power-portal-reference.md). diff --git a/dev-itpro/powerplatform/power-portal-reference.md b/dev-itpro/powerplatform/power-portal-reference.md index 0b146811f3..2c070378af 100644 --- a/dev-itpro/powerplatform/power-portal-reference.md +++ b/dev-itpro/powerplatform/power-portal-reference.md @@ -1,5 +1,5 @@ --- -title: "Power Apps portals with Business Central" +title: "Power Apps portals with [!INCLUDE[prodshort](../developer/includes/prodshort.md)]" ms.custom: na ms.date: 08/12/2020 ms.reviewer: solsen @@ -10,27 +10,27 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Power Apps portals with Business Central +# Power Apps portals with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] [!include[banner](../includes/banner.md)] > [!IMPORTANT] -> This functionality requires version 10.0.12 for Business Central apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). +> This functionality requires version 10.0.12 for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -Power Apps portals will enable create, update, and delete (CRUD) operations to Business Central entities that are available as virtual entities in Common Data Service. This topic explains the scenarios that are implemented in Power Apps portals for Business Central apps. +Power Apps portals will enable create, update, and delete (CRUD) operations to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities that are available as virtual entities in Common Data Service. This topic explains the scenarios that are implemented in Power Apps portals for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. ## Anonymous access from Power Apps portals -Collaboration scenarios in business processes such as bidding or onboarding of prospects in Business Central require that external users participate from the Power Apps portal, even though they aren't users in Business Central apps. The simplicity of anonymous access is appealing in these types of scenarios because the users, who might not be Business Central apps users, don't have to sign in. However, they are expected to perform CRUD operations in Business Central to complete any meaningful tasks in the business processes. +Collaboration scenarios in business processes such as bidding or onboarding of prospects in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] require that external users participate from the Power Apps portal, even though they aren't users in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. The simplicity of anonymous access is appealing in these types of scenarios because the users, who might not be [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps users, don't have to sign in. However, they are expected to perform CRUD operations in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] to complete any meaningful tasks in the business processes. -To ensure that only the required entities are enabled for anonymous access, a user in Business Central must be designated as the user who is used for anonymous access. This designation is configured in the **Anonymous portal access user ID** field on the **Virtual entity** tab on the **System parameters** page (**System administration \> System parameters**). The designated user can then be assigned to duties and security roles to control access to specific data that must be made available to all users who will interact anonymously from the Power Portal. +To ensure that only the required entities are enabled for anonymous access, a user in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] must be designated as the user who is used for anonymous access. This designation is configured in the **Anonymous portal access user ID** field on the **Virtual entity** tab on the **System parameters** page (**System administration \> System parameters**). The designated user can then be assigned to duties and security roles to control access to specific data that must be made available to all users who will interact anonymously from the Power Portal. Note that because this scenario involves anonymous access, the only user context that matters, from a security perspective, is the user who is designated in the **Anonymous portal access user ID** field. ## Authenticated access from Power Apps portals -Fully authenticated user access from Power Apps portals to Business Central lets users in Business Central also interact from Power Apps portals. A user who signs in to the Power Apps portal is also a known user in Business Central who has appropriate security roles based on job requirements. These roles govern the security access to data for the authenticated user in Power Portal. In addition, any Business Central user that is expected to also use Power Apps portal to access Business Central data must also belong to the **CDSVirtualEntityAuthenticatedPortalUser** security role. This provides an additional layer of security and also provides a way to know the total users that are authorized to access from Power Apps portals. +Fully authenticated user access from Power Apps portals to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] lets users in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] also interact from Power Apps portals. A user who signs in to the Power Apps portal is also a known user in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] who has appropriate security roles based on job requirements. These roles govern the security access to data for the authenticated user in Power Portal. In addition, any [!INCLUDE[prodshort](../developer/includes/prodshort.md)] user that is expected to also use Power Apps portal to access [!INCLUDE[prodshort](../developer/includes/prodshort.md)] data must also belong to the **CDSVirtualEntityAuthenticatedPortalUser** security role. This provides an additional layer of security and also provides a way to know the total users that are authorized to access from Power Apps portals. -Because Power Apps portals authentication is linked to the Contacts entity in Common Data Service, a mapping must be established between the Common Data Service contact and the corresponding user in Business Central. This mapping can be done by adding entries to the **msdyn\_externalportalusermapping** entity. From a security perspective, the scope of virtual entities that are made available to authenticated users must be configured as **Global** in the Power Apps portal. +Because Power Apps portals authentication is linked to the Contacts entity in Common Data Service, a mapping must be established between the Common Data Service contact and the corresponding user in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. This mapping can be done by adding entries to the **msdyn\_externalportalusermapping** entity. From a security perspective, the scope of virtual entities that are made available to authenticated users must be configured as **Global** in the Power Apps portal. -When authenticated users from a different tenant need to be added to Business Central as users, you must use the [Create new user](../sysadmin/tasks/create-new-users.md) process in Business Central. This process adds cross-tenant users as Microsoft Azure Active Directory (Azure AD) business-to-business (B2B) guest users. +When authenticated users from a different tenant need to be added to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] as users, you must use the [Create new user](../sysadmin/tasks/create-new-users.md) process in [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. This process adds cross-tenant users as Microsoft Azure Active Directory (Azure AD) business-to-business (B2B) guest users. From c263bb1bac02d887479e82e6f0a3e8b73ae65d61 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 13:03:27 +0200 Subject: [PATCH 123/950] Update devenv-application-insights-for-extensions.md --- .../developer/devenv-application-insights-for-extensions.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md index e773136df6..33493cd161 100644 --- a/dev-itpro/developer/devenv-application-insights-for-extensions.md +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -17,8 +17,10 @@ author: jswymer This article describes how to develop an extension to send telemetry data to an Azure Application Insights for monitoring and analyzing. [!INCLUDE[prodshort](includes/prodshort.md)] emits telemetry data for several operations that occur when extension code is run. You can configure an extension to send this telemetry data to a specific Application Insights resource on Microsoft Azure. For an overview about the telemetry with Application Insights, see [Monitoring and Analyzing Telemetry](../administration/telemetry-overview.md). +This feature targets publishers of per-tenant extensions to give them insight into issues in their extension before partners and customers report them. + > [!NOTE] -> This feature targets publishers of per-tenant extensions to give them insight into issues in their extension before partners and customers report them. This feature is not supported for AppSource extensions, because these extensions are automatically set up to send telemetry to Application Insights. +> This feature is not supported for AppSource extensions, because these extensions are automatically set up to send telemetry to Application Insights. ## Get an Application Insights resource in Azure @@ -30,7 +32,7 @@ The Application Insights resource is assigned an instrumentation key. Copy this ## Add the Application Insights Key to the extension's app.json -The next step is to add `"applicationInsightsKey"`setting the extension's app.json as shown: +The next step is to add the `"applicationInsightsKey"`setting the extension's app.json as shown: ``` "applicationInsightsKey": [""] From e773890e88266185f85752ae9a3ff357fd994d82 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 13:04:32 +0200 Subject: [PATCH 124/950] Update devenv-application-insights-for-extensions.md --- .../developer/devenv-application-insights-for-extensions.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md index 33493cd161..d2bee89706 100644 --- a/dev-itpro/developer/devenv-application-insights-for-extensions.md +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -20,8 +20,7 @@ This article describes how to develop an extension to send telemetry data to an This feature targets publishers of per-tenant extensions to give them insight into issues in their extension before partners and customers report them. > [!NOTE] -> This feature is not supported for AppSource extensions, because these extensions are automatically set up to send telemetry to Application Insights. - +> This feature is not supported for AppSource extensions. ## Get an Application Insights resource in Azure From b5c6caf016adaf0d87e3f455227fc42b14014f81 Mon Sep 17 00:00:00 2001 From: jswymer Date: Wed, 12 Aug 2020 13:06:46 +0200 Subject: [PATCH 125/950] Update devenv-application-insights-for-extensions.md --- .../developer/devenv-application-insights-for-extensions.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md index d2bee89706..7f62ec2a8b 100644 --- a/dev-itpro/developer/devenv-application-insights-for-extensions.md +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -26,8 +26,7 @@ This feature targets publishers of per-tenant extensions to give them insight in The first thing to do is to create an Application Insights resource in Azure if you don't have one. For more information, see [Create an Application Insights resource](/azure/azure-monitor/app/create-new-resource). -The Application Insights resource is assigned an instrumentation key. Copy this key because you'll need it to enable Application Insights in the [!INCLUDE[prodadmincenter](../developer/includes/prodadmincenter.md)] - +The Application Insights resource is assigned an instrumentation key, which you can see on the **Overview** page for the resource in Azure. Copy this key because you'll need it to enable Application Insights in the extension. ## Add the Application Insights Key to the extension's app.json From 579dae8e110c7d892381dfe84cebf31f6eb15bee Mon Sep 17 00:00:00 2001 From: jswymer Date: Thu, 13 Aug 2020 10:41:37 +0200 Subject: [PATCH 126/950] Update devenv-json-files.md --- dev-itpro/developer/devenv-json-files.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-itpro/developer/devenv-json-files.md b/dev-itpro/developer/devenv-json-files.md index c20f71bcfe..9390f2a48c 100644 --- a/dev-itpro/developer/devenv-json-files.md +++ b/dev-itpro/developer/devenv-json-files.md @@ -51,6 +51,7 @@ The following table describes the settings in the `app.json` file: |features|No|Specifies a list of options for translations. The `TranslationFile` option generates a `\Translations` folder that is populated with the .xlf file that contains all the labels, label properties, and report labels that you are using in the extension. The `GenerateCaptions` option depends on the `TranslationFile` setting. It generates captions for objects that do not have a `Caption` or `CaptionML` specified, these are then written to the .xlf file.
The syntax is `"features": [ "TranslationFile", "GenerateCaptions" ]`. For more information, see [Working with Translation Files](devenv-work-with-translation-files.md)| |internalsVisibleTo|No|Specifies a list of modules that have access to the objects that are marked as `Internal` using the **Access** property from the current module.
The syntax is `{ "appId": "d6c3f231-08d3-4681-996f-261c06500e1a", "name": "TheConsumer", "publisher": "Microsoft"}]`. For more information see [Access Property](properties/devenv-access-property.md) and [InternalEvent Attribute](methods/devenv-internal-attribute.md).| |propagateDependencies|No|Specifies whether the dependencies of this project should be propagated as direct dependencies of projects that depend on this one. Default is `false`. If set to `true` then any dependencies of the current package will be visible to consumers of the package. For example, if A depends on B that depends on C, by default, A will not be able to use types defined in C. If B has `"propagateDependencies" : "true"`, then A will be able to use types defined in C without taking a direct dependency.
**Note:** `propagateDependencies` applies to all dependencies, there is no option to exclude specific dependencies.| +|applicationInsightsKey|The instrumentation key of the Azure Application Insights resource for monitoring operations, for example, like app secrets retrieval by extensions.

For more information, see [Monitoring and Analyzing Telemetry](../administrartion/telemetry-overview.md).| ## Launch.json file From cf36e729e8f67e31570e7485c131effc9e1a2466 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 14:15:24 +0200 Subject: [PATCH 127/950] Update admin-reference.md --- dev-itpro/powerplatform/admin-reference.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev-itpro/powerplatform/admin-reference.md b/dev-itpro/powerplatform/admin-reference.md index 8185ff5e69..1434d29c63 100644 --- a/dev-itpro/powerplatform/admin-reference.md +++ b/dev-itpro/powerplatform/admin-reference.md @@ -1,5 +1,5 @@ --- -title: "[!INCLUDE[prodshort](../developer/includes/prodshort.md)] and Common Data Service admin reference" +title: "Business Central and Common Data Service admin reference" ms.custom: na ms.date: 08/12/2020 ms.reviewer: solsen @@ -10,7 +10,8 @@ ms.service: "dynamics365-business-central" author: solsen --- -# [!INCLUDE[prodshort](../developer/includes/prodshort.md)] and Common Data Service admin reference +# Business Central and Common Data Service admin reference + [!include[banner](../includes/banner.md)] > [!IMPORTANT] From a680e78b998832f94c77b7181df995035e69ac3e Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 14:16:15 +0200 Subject: [PATCH 128/950] Update application-lifecycle-management.md --- dev-itpro/powerplatform/application-lifecycle-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/powerplatform/application-lifecycle-management.md b/dev-itpro/powerplatform/application-lifecycle-management.md index 7d1e6f6cd8..e789494fe4 100644 --- a/dev-itpro/powerplatform/application-lifecycle-management.md +++ b/dev-itpro/powerplatform/application-lifecycle-management.md @@ -55,6 +55,6 @@ One or more ISV solutions will take a dependency on the MicrosoftOperationsERPVE The established guidelines and ALM for entity development in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] ensure that there are no conflicting entity names across ISV solutions. Therefore, no conflicts of this type can occur when virtual entities are generated in Common Data Service for custom [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities from multiple ISV solutions. All virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities, including custom entities, will have the "mserp\_" prefix that was mentioned earlier. -### Managing a Finance and Operation instance in a Common Data Service environment for virtual entities +### Managing a [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance in a Common Data Service environment for virtual entities One [!INCLUDE[prodshort](../developer/includes/prodshort.md)] instance must be linked to a Common Data Service environment for virtual entities. The connection setup information that is required is captured in a virtual entity data source for [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. This data source is included in the MicrosoftOperationsERPCatalog solution. From 0c81615189672858425471a2096ca7e80d92d1e9 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 14:19:24 +0200 Subject: [PATCH 129/950] wip --- dev-itpro/powerplatform/admin-reference.md | 2 +- dev-itpro/powerplatform/application-lifecycle-management.md | 2 +- dev-itpro/powerplatform/entity-modeling.md | 4 ++-- dev-itpro/powerplatform/faq.md | 4 ++-- dev-itpro/powerplatform/overview.md | 2 +- dev-itpro/powerplatform/power-portal-reference.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dev-itpro/powerplatform/admin-reference.md b/dev-itpro/powerplatform/admin-reference.md index 1434d29c63..d5b8cfd3b7 100644 --- a/dev-itpro/powerplatform/admin-reference.md +++ b/dev-itpro/powerplatform/admin-reference.md @@ -10,7 +10,7 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Business Central and Common Data Service admin reference +# Business Central and Common Data Service Admin Reference [!include[banner](../includes/banner.md)] diff --git a/dev-itpro/powerplatform/application-lifecycle-management.md b/dev-itpro/powerplatform/application-lifecycle-management.md index e789494fe4..286087876f 100644 --- a/dev-itpro/powerplatform/application-lifecycle-management.md +++ b/dev-itpro/powerplatform/application-lifecycle-management.md @@ -10,7 +10,7 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Application lifecycle management for solutions that use virtual entities +# Application Lifecycle Management for Solutions that use Virtual Entities [!include[banner](../includes/banner.md)] diff --git a/dev-itpro/powerplatform/entity-modeling.md b/dev-itpro/powerplatform/entity-modeling.md index c15e48fc5c..51815812e7 100644 --- a/dev-itpro/powerplatform/entity-modeling.md +++ b/dev-itpro/powerplatform/entity-modeling.md @@ -10,7 +10,7 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Entity modeling +# Entity Modeling [!include[banner](../includes/banner.md)] @@ -23,7 +23,7 @@ Building an app requires capabilities to perform relational modeling between ent ## Generating virtual entities -By default, virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps don't exist in Common Data Service. A user must query the catalog entity to view the entities that are available in the linked instance of [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. From the catalog, the user can select one or more entities, and then request that Common Data Service generate the virtual entities. This procedure is explained in later sections. +By default, virtual entities for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps do not exist in Common Data Service. A user must query the catalog entity to view the entities that are available in the linked instance of [!INCLUDE[prodshort](../developer/includes/prodshort.md)]. From the catalog, the user can select one or more entities, and then request that Common Data Service generate the virtual entities. This procedure is explained in later sections. ## Entity fields diff --git a/dev-itpro/powerplatform/faq.md b/dev-itpro/powerplatform/faq.md index 89ca074f45..d07e08b1eb 100644 --- a/dev-itpro/powerplatform/faq.md +++ b/dev-itpro/powerplatform/faq.md @@ -1,5 +1,5 @@ --- -title: "[!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities FAQ" +title: "Business Central virtual entities FAQ" ms.custom: na ms.date: 08/12/2020 ms.reviewer: solsen @@ -10,7 +10,7 @@ ms.service: "dynamics365-business-central" author: solsen --- -# [!INCLUDE[prodshort](../developer/includes/prodshort.md)] virtual entities FAQ +# Business Central Virtual Entities FAQ [!include[banner](../includes/banner.md)] diff --git a/dev-itpro/powerplatform/overview.md b/dev-itpro/powerplatform/overview.md index c5998ab761..ea9bcd52b5 100644 --- a/dev-itpro/powerplatform/overview.md +++ b/dev-itpro/powerplatform/overview.md @@ -10,7 +10,7 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Microsoft Power Platform integration with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] +# Microsoft Power Platform Integration with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] [!include[banner](../includes/banner.md)] diff --git a/dev-itpro/powerplatform/power-portal-reference.md b/dev-itpro/powerplatform/power-portal-reference.md index 2c070378af..84b0d128d9 100644 --- a/dev-itpro/powerplatform/power-portal-reference.md +++ b/dev-itpro/powerplatform/power-portal-reference.md @@ -10,7 +10,7 @@ ms.service: "dynamics365-business-central" author: solsen --- -# Power Apps portals with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] +# Power Apps Portals with [!INCLUDE[prodshort](../developer/includes/prodshort.md)] [!include[banner](../includes/banner.md)] From 9e6aa8c3fa7c282d4369ad3055658aaee0de472d Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 14:26:03 +0200 Subject: [PATCH 130/950] wip --- dev-itpro/TOC.md | 7 +++++++ dev-itpro/powerplatform/overview.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 91427bc6c2..0bbff2f693 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -634,6 +634,13 @@ ## Integrating with Common Data Service ### [Custom Integration with Common Data Service](administration/administration-custom-cds-integration.md) ### [AL Proxy Table Generator](developer/devenv-al-table-proxy-generator.md) +## Integrating with Microsoft Power Platform +### [Business Central and Common Data Service Admin Reference](powerplatform/admin-reference.md) +### [Application Lifecycle Management for Solutions that use Virtual Entities](powerplatform/application-lifecycle-management.md) +### [Entity Modeling](powerplatform/entity-modeling.md) +### [FAQ](powerplatform/faq.md) +### [Microsoft Power Platform Integration with Business Central](powerplatform/overview.md) +### [Power Apps Portals with Business Central](powerplatform/power-portal-reference.md) ## [Dynamics 365 Business Central API](/dynamics-nav/api-reference/v1.0/index) diff --git a/dev-itpro/powerplatform/overview.md b/dev-itpro/powerplatform/overview.md index ea9bcd52b5..576b8371b0 100644 --- a/dev-itpro/powerplatform/overview.md +++ b/dev-itpro/powerplatform/overview.md @@ -17,7 +17,7 @@ author: solsen > [!IMPORTANT] > This functionality requires version 10.0.12 for [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps, while service update 189 is required for Common Data Service. The release information for Common Data Service is published on the [latest version availability page](https://docs.microsoft.com/business-applications-release-notes/dynamics/released-versions/dynamics-365ce#all-version-availability). -[!INCLUDE[prodshort](../developer/includes/prodshort.md)] is a virtual data source in Common Data Service, and enables full create, read, update, delete (CRUD) operations from Common Data Service and Microsoft Power Platform. By definition, the data for virtual entities doesn't reside in Common Data Service. Instead, it continues to reside in the application where it belongs. To enable CRUD operations on [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities from Common Data Service, entities must be made available as virtual entities in Common Data Service. The allows CRUD operations to be performed, from Common Data Service and Microsoft Power Platform, on data that resides in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. +[!INCLUDE[prodshort](../developer/includes/prodshort.md)] is a virtual data source in Common Data Service, and enables full create, read, update, delete (CRUD) operations from Common Data Service and Microsoft Power Platform. By definition, the data for virtual entities does not reside in Common Data Service. Instead, it continues to reside in the application where it belongs. To enable CRUD operations on [!INCLUDE[prodshort](../developer/includes/prodshort.md)] entities from Common Data Service, entities must be made available as virtual entities in Common Data Service. The allows CRUD operations to be performed, from Common Data Service and Microsoft Power Platform, on data that resides in [!INCLUDE[prodshort](../developer/includes/prodshort.md)] apps. ## Prerequisite reading From 713dc41e8f42ece35616781fee2acd3ef9766a71 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 14:27:44 +0200 Subject: [PATCH 131/950] Update TOC.md --- dev-itpro/TOC.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 0bbff2f693..356de33310 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -635,12 +635,12 @@ ### [Custom Integration with Common Data Service](administration/administration-custom-cds-integration.md) ### [AL Proxy Table Generator](developer/devenv-al-table-proxy-generator.md) ## Integrating with Microsoft Power Platform -### [Business Central and Common Data Service Admin Reference](powerplatform/admin-reference.md) -### [Application Lifecycle Management for Solutions that use Virtual Entities](powerplatform/application-lifecycle-management.md) -### [Entity Modeling](powerplatform/entity-modeling.md) -### [FAQ](powerplatform/faq.md) ### [Microsoft Power Platform Integration with Business Central](powerplatform/overview.md) +### [Entity Modeling](powerplatform/entity-modeling.md) +### [Application Lifecycle Management for Solutions that use Virtual Entities](powerplatform/application-lifecycle-management.md) +### [Business Central and Common Data Service Admin Reference](powerplatform/admin-reference.md) ### [Power Apps Portals with Business Central](powerplatform/power-portal-reference.md) +### [FAQ](powerplatform/faq.md) ## [Dynamics 365 Business Central API](/dynamics-nav/api-reference/v1.0/index) From 13ad9f5e3172667c5f50f86fe05a2d366a0bd393 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 14:29:07 +0200 Subject: [PATCH 132/950] Update TOC.md --- dev-itpro/TOC.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 356de33310..101769cecb 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -635,14 +635,18 @@ ### [Custom Integration with Common Data Service](administration/administration-custom-cds-integration.md) ### [AL Proxy Table Generator](developer/devenv-al-table-proxy-generator.md) ## Integrating with Microsoft Power Platform + + ### [Microsoft Power Platform Integration with Business Central](powerplatform/overview.md) ### [Entity Modeling](powerplatform/entity-modeling.md) ### [Application Lifecycle Management for Solutions that use Virtual Entities](powerplatform/application-lifecycle-management.md) ### [Business Central and Common Data Service Admin Reference](powerplatform/admin-reference.md) ### [Power Apps Portals with Business Central](powerplatform/power-portal-reference.md) ### [FAQ](powerplatform/faq.md) + + ## [Dynamics 365 Business Central API](/dynamics-nav/api-reference/v1.0/index) - + # Removed or deprecated features ## Deprecated Tables From 8d944454f58733eaec5f49e2c1e6349258bca339 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 14:31:42 +0200 Subject: [PATCH 133/950] wip --- dev-itpro/TOC.md | 12 ++++++------ ...min-reference.md => powerplat-admin-reference.md} | 0 ...ment.md => powerplat-app-lifecycle-management.md} | 0 ...tity-modeling.md => powerplat-entity-modeling.md} | 0 dev-itpro/powerplatform/{faq.md => powerplat-faq.md} | 0 .../{overview.md => powerplat-overview.md} | 0 ...al-reference.md => powerplat-portal-reference.md} | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename dev-itpro/powerplatform/{admin-reference.md => powerplat-admin-reference.md} (100%) rename dev-itpro/powerplatform/{application-lifecycle-management.md => powerplat-app-lifecycle-management.md} (100%) rename dev-itpro/powerplatform/{entity-modeling.md => powerplat-entity-modeling.md} (100%) rename dev-itpro/powerplatform/{faq.md => powerplat-faq.md} (100%) rename dev-itpro/powerplatform/{overview.md => powerplat-overview.md} (100%) rename dev-itpro/powerplatform/{power-portal-reference.md => powerplat-portal-reference.md} (100%) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 101769cecb..1563decd17 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -637,12 +637,12 @@ ## Integrating with Microsoft Power Platform -### [Microsoft Power Platform Integration with Business Central](powerplatform/overview.md) -### [Entity Modeling](powerplatform/entity-modeling.md) -### [Application Lifecycle Management for Solutions that use Virtual Entities](powerplatform/application-lifecycle-management.md) -### [Business Central and Common Data Service Admin Reference](powerplatform/admin-reference.md) -### [Power Apps Portals with Business Central](powerplatform/power-portal-reference.md) -### [FAQ](powerplatform/faq.md) +### [Microsoft Power Platform Integration with Business Central](powerplatform/powerplat-overview.md) +### [Entity Modeling](powerplatform/powerplat-entity-modeling.md) +### [Application Lifecycle Management for Solutions that use Virtual Entities](powerplatform/powerplat-app-lifecycle-management.md) +### [Business Central and Common Data Service Admin Reference](powerplatform/powerplat-admin-reference.md) +### [Power Apps Portals with Business Central](powerplatform/powerplat-portal-reference.md) +### [FAQ](powerplatform/powerplat-faq.md) ## [Dynamics 365 Business Central API](/dynamics-nav/api-reference/v1.0/index) diff --git a/dev-itpro/powerplatform/admin-reference.md b/dev-itpro/powerplatform/powerplat-admin-reference.md similarity index 100% rename from dev-itpro/powerplatform/admin-reference.md rename to dev-itpro/powerplatform/powerplat-admin-reference.md diff --git a/dev-itpro/powerplatform/application-lifecycle-management.md b/dev-itpro/powerplatform/powerplat-app-lifecycle-management.md similarity index 100% rename from dev-itpro/powerplatform/application-lifecycle-management.md rename to dev-itpro/powerplatform/powerplat-app-lifecycle-management.md diff --git a/dev-itpro/powerplatform/entity-modeling.md b/dev-itpro/powerplatform/powerplat-entity-modeling.md similarity index 100% rename from dev-itpro/powerplatform/entity-modeling.md rename to dev-itpro/powerplatform/powerplat-entity-modeling.md diff --git a/dev-itpro/powerplatform/faq.md b/dev-itpro/powerplatform/powerplat-faq.md similarity index 100% rename from dev-itpro/powerplatform/faq.md rename to dev-itpro/powerplatform/powerplat-faq.md diff --git a/dev-itpro/powerplatform/overview.md b/dev-itpro/powerplatform/powerplat-overview.md similarity index 100% rename from dev-itpro/powerplatform/overview.md rename to dev-itpro/powerplatform/powerplat-overview.md diff --git a/dev-itpro/powerplatform/power-portal-reference.md b/dev-itpro/powerplatform/powerplat-portal-reference.md similarity index 100% rename from dev-itpro/powerplatform/power-portal-reference.md rename to dev-itpro/powerplatform/powerplat-portal-reference.md From 3100db1c3306d0568c8ebd8258eabd5e0ed598ea Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 15:14:26 +0200 Subject: [PATCH 134/950] AW0010 deprecated with 17.0 --- .openpublishing.redirection.json | 5 +++++ dev-itpro/developer/analyzers/uicop.md | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 6b2e890708..623ca243f0 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -5209,6 +5209,11 @@ "source_path": "dev-itpro/developer/readiness/readiness-develop-your-app.md", "redirect_url": "/dynamics365/business-central/dev-itpro/developer/devenv-checklist-submission", "redirect_document_id": false + }, + { + "source_path": "dev-itpro/developer/analyzers/uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md", + "redirect_url": "/dynamics365/business-central/dev-itpro/developer/analyzers/uicop", + "redirect_document_id": false } ] } diff --git a/dev-itpro/developer/analyzers/uicop.md b/dev-itpro/developer/analyzers/uicop.md index e40896e7a3..d3dc7039a8 100644 --- a/dev-itpro/developer/analyzers/uicop.md +++ b/dev-itpro/developer/analyzers/uicop.md @@ -29,7 +29,6 @@ UICop is an analyzer that enforces rules that must be respected by extensions me |[AW0007](uicop-aw0007-repeaterwithflowfiltercannotbedisplayed.md)|The Web client does not support displaying Repeater controls that contain FlowFilter fields.|The Web client does not support displaying Repeater controls that contain FlowFilter fields.|The FlowFiter field '{0}' in the Repeater control '{1}' cannot be displayed by the Web client.|WebClient|Error|true| |[AW0008](uicop-aw0008-repeatersisnotsupportedincardpages.md)|The Web client does not support displaying Repeater controls in pages of type Card, Document, and ListPlus.|The Web client does not support displaying Repeater controls in pages of type Card, Document, and ListPlus.|The repeater '{0}' is not supported by the Web client.|WebClient|Warning|true| |[AW0009](uicop-aw0009-blobbitmapusageonpagefielddeprecated.md)|Using a Blob with subtype Bitmap on a page field is deprecated. Instead use the Media/MediaSet data types.|Using a Blob with subtype Bitmap on a page field is deprecated. Instead use the Media/MediaSet data types.|Using a Blob with subtype Bitmap on a page field is deprecated. Instead use the Media/MediaSet data types.|WebClient|Warning|true| -|[AW0010](uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md)|A Repeater control used on a List page must be defined at the beginning of the area(Content) section.|A Repeater control used on a List page must be defined at the beginning of the area(Content) section.|A Repeater control used on a List page must be defined at the beginning of the area(Content) section.|WebClient|Warning|true| |[AW0011](uicop-aw0011-addpromotedonlyifallactionsmarkedpromoted.md)|Add PromotedOnly="true" to some or all promoted actions to avoid identical actions from appearing in both the promoted and default sections of the command bar.|Add PromotedOnly="true" to some or all promoted actions to avoid identical actions from appearing in both the promoted and default sections of the command bar.|Group "{0}" only contains promoted actions that are not set to PromotedOnly="true".|WebClient|Info|true| [//]: # (IMPORTANT: END>DO_NOT_EDIT) From 8e392fadfb21a17d207b804e6573c702fc12fb84 Mon Sep 17 00:00:00 2001 From: Susanne Windfeld Pedersen Date: Thu, 13 Aug 2020 15:15:58 +0200 Subject: [PATCH 135/950] deprecating --- .../uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {dev-itpro/developer/analyzers => properties}/uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md (100%) diff --git a/dev-itpro/developer/analyzers/uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md b/properties/uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md similarity index 100% rename from dev-itpro/developer/analyzers/uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md rename to properties/uicop-aw0010-repeatersingroupsnotsupportedinlistpages.md From d65efa516d9d28c4a59da1dbd032a98fc40cc38f Mon Sep 17 00:00:00 2001 From: jswymer Date: Mon, 17 Aug 2020 11:06:43 +0200 Subject: [PATCH 136/950] Update devenv-application-insights-for-extensions.md --- .../developer/devenv-application-insights-for-extensions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md index 7f62ec2a8b..9c55cfe674 100644 --- a/dev-itpro/developer/devenv-application-insights-for-extensions.md +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -17,7 +17,7 @@ author: jswymer This article describes how to develop an extension to send telemetry data to an Azure Application Insights for monitoring and analyzing. [!INCLUDE[prodshort](includes/prodshort.md)] emits telemetry data for several operations that occur when extension code is run. You can configure an extension to send this telemetry data to a specific Application Insights resource on Microsoft Azure. For an overview about the telemetry with Application Insights, see [Monitoring and Analyzing Telemetry](../administration/telemetry-overview.md). -This feature targets publishers of per-tenant extensions to give them insight into issues in their extension before partners and customers report them. +This feature targets publishers of per-tenant extensions to give them insight into issues in their extensions before partners and customers report them. > [!NOTE] > This feature is not supported for AppSource extensions. @@ -38,7 +38,7 @@ The next step is to add the `"applicationInsightsKey"`setting the extension's ap Replace `` with your key. -When done, build the extension package, then publish and install it as usual. When the extension is run from [!INCLUDE[prodshort](includes/prodshort.md)], Application Insights gathers the telemetry data for viewing. +When done, build the extension package, then publish and install it as usual. When the extension is run from [!INCLUDE[prodshort](includes/prodshort.md)], Application Insights gathers the telemetry data for viewing and analyzing. ## See Also [Getting Started with AL](devenv-get-started.md) From 3fbda585f35312eb65c13808e0a3568ae6376a5d Mon Sep 17 00:00:00 2001 From: Eva Dupont Date: Mon, 17 Aug 2020 12:48:57 +0200 Subject: [PATCH 137/950] Update TOC.md --- dev-itpro/TOC.md | 87 ++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index fa94a4452a..368d244b5d 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -1,6 +1,6 @@ # Get Started -## [Development and Administration](index.md) -## [FAQ](faq.md) +## [Get started with development and administration](index.md) +## [Frequently asked questions](faq.md) ## Help and Support ### [Resources for Help and Support](help-and-support.md) ### [Technical Support](technical-support.md) @@ -13,51 +13,50 @@ #### [Migrate Legacy Help to the Business Central Format](upgrade/migrate-help.md) #### [Custom Help Toolkit](help/custom-help-toolkit.md) #### [Custom Help Toolkit: The HtmlFromRepoGenerator tool](help/custom-help-toolkit-HtmlFromRepoGenerator.md) - -## Training and Readiness -### Learning Catalogs -#### [Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-catalog?toc=/dynamics365/business-central/dev-itpro/toc.json) -#### [Business Decision Maker Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-bus-decision-makers?toc=/dynamics365/business-central/dev-itpro/toc.json) -#### [Business User Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-bus-users?toc=/dynamics365/business-central/dev-itpro/toc.json) -#### [Developer Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-developers?toc=/dynamics365/business-central/dev-itpro/toc.json) -#### [Functional Consultant Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-functional-consultants?toc=/dynamics365/business-central/dev-itpro/toc.json) -#### [Pre-sales Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-presales?toc=/dynamics365/business-central/dev-itpro/toc.json) -#### [Sales Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-sales?toc=/dynamics365/business-central/dev-itpro/toc.json) - -### Readiness -#### [Build Your Business on Dynamics 365 Business Central](developer/readiness/readiness-welcome.md) -#### [Resell Different Solutions](developer/readiness/readiness-reseller.md) -#### [Integrate a 3rd Party Solution](developer/readiness/readiness-thirdparty-solution.md) -#### [Development of a Vertical Solution](developer/readiness/readiness-develop-vertical.md) -#### [Development of a Horizontal Solution](developer/readiness/readiness-develop-horizontal.md) -#### [Development of a Localization Solution](developer/readiness/readiness-develop-localization.md) -#### [Getting You Started with Building Apps](developer/readiness/readiness-add-on-apps-getting-you-started.md) -## Sell Business Central -### [Get Started as a Reseller of Business Central Online](administration/get-started-online.md) -### [Cloud Solution Provider program](/partner-center/csp-overview?toc=/dynamics365/business-central/dev-itpro/toc.json) -## Build apps for Business Central +## Roles +### Functional consultant +#### [Learning catalog](/dynamics365/business-central/readiness/readiness-learning-functional-consultants?toc=/dynamics365/business-central/dev-itpro/toc.json) +#### [Documentation]((/dynamics365/business-central/product-get-started?toc=/dynamics365/business-central/dev-itpro/toc.json) +### Developer +#### [Learning catalog](/dynamics365/business-central/readiness/readiness-learning-developers?toc=/dynamics365/business-central/dev-itpro/toc.json) +#### [Documentation](developer/devenv-dev-overview.md) +### Solution architect +#### [Learning catalog](/dynamics365/business-central/readiness/readiness-learning-functional-consultants?toc=/dynamics365/business-central/dev-itpro/toc.json) +#### [Documentation](administration/tenant-administration.md) +## Readiness +### Sell +#### [Become a Reseller](/dynamics365/business-central/product-sell?toc=/dynamics365/business-central/dev-itpro/toc.json) +#### [Get Started as a Reseller of Business Central Online](administration/get-started-online.md) +#### [Cloud Solution Provider program](/partner-center/csp-overview?toc=/dynamics365/business-central/dev-itpro/toc.json) +### Develop +#### [Extending Business Central](/dynamics365/business-central/about-develop-extensions?toc=/dynamics365/business-central/dev-itpro/toc.json) -### [Microsoft Responsibilities](deployment/microsoft-responsibilities.md) -### [Components and Capabilities](deployment/app-components.md) -### [Licensing](deployment/licensing.md) -### [Add your App to AppSource](administration/appsource.md) -### Embed Apps -#### [Embed App Overview](deployment/embed-app-overview.md) -#### [Qualification and Onboarding](deployment/embed-app-qualifications-onboarding.md) -#### [Creating Deployment Packages](embedapps/embed-app-deployment-package.md) -#### [Managing Embed Apps in Microsoft Lifecycle Services](deployment/embed-app-lifecycle-services.md) -#### [Using Application Family](deployment/embed-app-using-application-family.md) -#### App Management -##### [Introduction](administration/appmanagement/app-management-overview.md) -##### [App Management API](administration/appmanagement/app-management-api.md) +#### [Microsoft Responsibilities](deployment/microsoft-responsibilities.md) +#### [Components and Capabilities](deployment/app-components.md) +#### [Licensing](deployment/licensing.md) +#### [Add your App to AppSource](administration/appsource.md) +#### Get started with building apps +##### [Overview](developer/readiness/readiness-add-on-apps-getting-you-started.md) +##### [Development of a Vertical Solution](developer/readiness/readiness-develop-vertical.md) +##### [Development of a Horizontal Solution](developer/readiness/readiness-develop-horizontal.md) +##### [Development of a Localization Solution](developer/readiness/readiness-develop-localization.md) +#### Embed Apps +##### [Embed App Overview](deployment/embed-app-overview.md) +##### [Qualification and Onboarding](deployment/embed-app-qualifications-onboarding.md) +##### [Creating Deployment Packages](embedapps/embed-app-deployment-package.md) +##### [Managing Embed Apps in Microsoft Lifecycle Services](deployment/embed-app-lifecycle-services.md) +##### [Using Application Family](deployment/embed-app-using-application-family.md) +##### App Management +###### [Introduction](administration/appmanagement/app-management-overview.md) +###### [App Management API](administration/appmanagement/app-management-api.md) -### AppSource Validation -#### [Marketing Validation Checklist](developer/readiness/readiness-checklist-marketing.md) -#### [Marketing Validation FAQ](developer/readiness/readiness-marketing-validation-faq.md) -#### [Technical Validation Checklist](developer/devenv-checklist-submission.md) -#### [How to Make Compelling Videos](developer/readiness/readiness-how-to-make-compelling-videos.md) -#### [How to Create an Effective Sales Landing Page](developer/readiness/readiness-how-to-create-sales-landing-page.md) +#### AppSource Validation +##### [Marketing Validation Checklist](developer/readiness/readiness-checklist-marketing.md) +##### [Marketing Validation FAQ](developer/readiness/readiness-marketing-validation-faq.md) +##### [Technical Validation Checklist](developer/devenv-checklist-submission.md) +##### [How to Make Compelling Videos](developer/readiness/readiness-how-to-make-compelling-videos.md) +##### [How to Create an Effective Sales Landing Page](developer/readiness/readiness-how-to-create-sales-landing-page.md) # Administration ## [Administration of Business Central Online](administration/tenant-administration.md) From 9a3be9203429835a52ed75aa09ef9d1a7c2ab523 Mon Sep 17 00:00:00 2001 From: Eva Dupont Date: Mon, 17 Aug 2020 12:52:10 +0200 Subject: [PATCH 138/950] Update TOC.md --- dev-itpro/TOC.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 368d244b5d..89d8b3e235 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -28,6 +28,9 @@ #### [Become a Reseller](/dynamics365/business-central/product-sell?toc=/dynamics365/business-central/dev-itpro/toc.json) #### [Get Started as a Reseller of Business Central Online](administration/get-started-online.md) #### [Cloud Solution Provider program](/partner-center/csp-overview?toc=/dynamics365/business-central/dev-itpro/toc.json) +#### [Pre-sales Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-presales?toc=/dynamics365/business-central/dev-itpro/toc.json) +#### [Sales Learning Catalog](/dynamics365/business-central/readiness/readiness-learning-sales?toc=/dynamics365/business-central/dev-itpro/toc.json) + ### Develop #### [Extending Business Central](/dynamics365/business-central/about-develop-extensions?toc=/dynamics365/business-central/dev-itpro/toc.json) From 9fe5ddf6f0754d38f494e5c4dccc8af311001530 Mon Sep 17 00:00:00 2001 From: Eva Dupont Date: Mon, 17 Aug 2020 13:08:01 +0200 Subject: [PATCH 139/950] Update TOC.md --- dev-itpro/TOC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 89d8b3e235..42b1ba7dc3 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -16,7 +16,7 @@ ## Roles ### Functional consultant #### [Learning catalog](/dynamics365/business-central/readiness/readiness-learning-functional-consultants?toc=/dynamics365/business-central/dev-itpro/toc.json) -#### [Documentation]((/dynamics365/business-central/product-get-started?toc=/dynamics365/business-central/dev-itpro/toc.json) +#### [Documentation](/dynamics365/business-central/product-get-started?toc=/dynamics365/business-central/dev-itpro/toc.json) ### Developer #### [Learning catalog](/dynamics365/business-central/readiness/readiness-learning-developers?toc=/dynamics365/business-central/dev-itpro/toc.json) #### [Documentation](developer/devenv-dev-overview.md) From c6dd192e142dc88a674a978e97b33f2fcc648554 Mon Sep 17 00:00:00 2001 From: jswymer Date: Mon, 17 Aug 2020 13:49:50 +0200 Subject: [PATCH 140/950] Update devenv-application-insights-for-extensions.md --- .../developer/devenv-application-insights-for-extensions.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev-itpro/developer/devenv-application-insights-for-extensions.md b/dev-itpro/developer/devenv-application-insights-for-extensions.md index 9c55cfe674..7e4dd6c462 100644 --- a/dev-itpro/developer/devenv-application-insights-for-extensions.md +++ b/dev-itpro/developer/devenv-application-insights-for-extensions.md @@ -2,7 +2,7 @@ title: Sending Extension Telemetry to Azure Application Insights description: Describes how to configure an extension to send telemetry data to Azure Application Insights. ms.custom: na -ms.date: 12/08/2020 +ms.date: 08/17/2020 ms.reviewer: na ms.suite: na ms.tgt_pltfrm: na @@ -44,4 +44,5 @@ When done, build the extension package, then publish and install it as usual. Wh [Getting Started with AL](devenv-get-started.md) [Publishing and Installing Extensions](devenv-how-publish-and-install-an-extension-v2.md) [JSON Files](devenv-json-files.md) -[Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) \ No newline at end of file +[Viewing telemetry data in Application Insights](../administration/telemetry-overview.md) +[LogMessage Method](../developer/methods-auto/session/session-logmessage-string-string-verbosity-dataclassification-telemetryscope-string-string-string-string-method.md) \ No newline at end of file From c9e4960382c9669a4d7be478544a2b9cdf829e2e Mon Sep 17 00:00:00 2001 From: jswymer Date: Mon, 17 Aug 2020 13:54:04 +0200 Subject: [PATCH 141/950] Update telemetry-overview.md --- dev-itpro/administration/telemetry-overview.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-itpro/administration/telemetry-overview.md b/dev-itpro/administration/telemetry-overview.md index 854094cb14..578d8e2178 100644 --- a/dev-itpro/administration/telemetry-overview.md +++ b/dev-itpro/administration/telemetry-overview.md @@ -80,3 +80,4 @@ For more information, see [Business Central BCTech repository on GitHub](https:/ [Managing Environments](tenant-admin-center-environments.md) [Managing Tenant Notifications](tenant-admin-center-notifications.md) [Introduction to automation APIs](itpro-introduction-to-automation-apis.md) +[LogMessage Method](../developer/methods-auto/session/session-logmessage-string-string-verbosity-dataclassification-telemetryscope-string-string-string-string-method.md) \ No newline at end of file From 91953145f451362b6871a3ab48fd3cc2c61a421a Mon Sep 17 00:00:00 2001 From: jswymer Date: Mon, 17 Aug 2020 14:14:58 +0200 Subject: [PATCH 142/950] updates --- dev-itpro/TOC.md | 1 + ...system-requirement-business-central-v17.md | 178 ++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 dev-itpro/deployment/system-requirement-business-central-v17.md diff --git a/dev-itpro/TOC.md b/dev-itpro/TOC.md index 4f417c1e61..819edbd480 100644 --- a/dev-itpro/TOC.md +++ b/dev-itpro/TOC.md @@ -665,6 +665,7 @@ ## Deployment ### [Overview](deployment/deployment.md) ### [Features not implemented in on-premises deployments](features-not-implemented-on-premises.md) +### [System Requirements 2020 Release Wave 2](deployment/system-requirement-business-central-v17.md) ### [System Requirements 2020 Release Wave 1](deployment/system-requirement-business-central-v16.md) ### [System Requirements 2019 Release Wave 2](deployment/system-requirement-business-central-v15.md) ### [System Requirements April '19](deployment/system-requirement-business-central.md) diff --git a/dev-itpro/deployment/system-requirement-business-central-v17.md b/dev-itpro/deployment/system-requirement-business-central-v17.md new file mode 100644 index 0000000000..74e9139065 --- /dev/null +++ b/dev-itpro/deployment/system-requirement-business-central-v17.md @@ -0,0 +1,178 @@ +--- +title: System Requirements for Business Central 2020 Release Wave 1 +description: This article provides the specifications of minimum hardware and software requirements to install and run Business Central on-premises. +ms.custom: na +ms.suite: na +ms.tgt_pltfrm: na +ms.topic: article +ms.service: "dynamics365-business-central" +ms.date: 05/06/2020 +author: jswymer +--- +# System Requirements for [!INCLUDE[prodlong](../developer/includes/prodlong.md)] 2020 Release Wave 1 + +The following sections list the minimum hardware and software requirements to use or connect to [!INCLUDE[prodshort](../developer/includes/prodshort.md)] online, and to install and run [!INCLUDE[prodshort](../developer/includes/prodshort.md)] on-premises (version 16). **Minimum** means that later versions \(such as SP1, SP2, or R2 versions\) of a required software product are also supported. + +> [!NOTE] +> [!INCLUDE[prodsetup](../developer/includes/prodsetup.md)] installs some software if it'sn't already present in the target computer. For more information, see the "Additional Information" section for each component. + +## Client Components + +### Web Client Requirements + The following table shows the minimum system requirements for the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Web client on-premises. + +||| +|------|-----| +|Supported browsers|Recommended browsers:
  • New Microsoft Edge for Windows
  • Google Chrome 81.0 for Windows
  • Mozilla Firefox 75.0 for Windows
  • Safari 12.0 for macOS
Other supported browsers:
  • Internet Explorer 11
  • Microsoft Edge Legacy
Cookies and JavaScript must be enabled in the browser.| +|Business inbox in Outlook|
  • Microsoft Office 365, Microsoft Office 2019, or Microsoft Office 2016.
| +|Sending data to Excel|
  • Microsoft Office 365, Microsoft Office 2019, or Microsoft Office 2016.
| +|Editing in Excel using the Excel Add-in |
  • Excel 2019, Excel 2016, or Excel Online.

    For more information, see [Exporting Your Business Data to Excel](/dynamics365/business-central/about-export-data).
| +|SharePoint Online links|
  • Microsoft Office 2019, Microsoft Office 2016, or Microsoft Office 365.
| +|Printing reports to Excel or Word|
  • Microsoft Office 2019, Microsoft Office 2016, or Microsoft Office 365.
| +|Additional information|If you experience problems using the [!INCLUDE[nav_web](../developer/includes/nav_web_md.md)], you can try to turn off browser tools, such as translator tools that may run in the background.| + +### [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Tablet Client and Phone Client \(in a Browser\) Requirements + The following table shows the minimum system requirements for the [!INCLUDE[nav_tablet](../developer/includes/nav_tablet_md.md)] and [!INCLUDE[nav_phone](../developer/includes/nav_phone_md.md)] running in a desktop browser when used for development and testing purposes. + +||| +|------|-----| +|Server component|Identical to the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Web client.| +|Supported browsers|Identical to the [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Web client.| + +### [!INCLUDE[nav_uni_app_md](../developer/includes/nav_uni_app_md.md)] Requirements + The following table shows the minimum system requirements for the [!INCLUDE[nav_uni_app](../developer/includes/nav_uni_app_md.md)]. + +For the latest information, see the app in the Windows Store, App Store, or Google Play. +[![Windows Store](../developer/media/install-mobile-app/windowsstore.png)](https://go.microsoft.com/fwlink/?LinkId=734848) +[![App Store](../developer/media/install-mobile-app/appstore.png)](https://go.microsoft.com/fwlink/?LinkId=734847) [![Google Play](../developer/media/install-mobile-app/googleplay.png)](https://go.microsoft.com/fwlink/?LinkId=734849) + +||| +|------|-----| +|Supported operating systems|
  • Windows 10 S, Home, Pro, Enterprise, or Education \(32-bit and 64-bit editions\).
  • Android 6.0 or higher (tablet and phone).
  • iOS 10.0 or higher (iPad and iPhone).
| +|Additional hardware|
  • 1-GB RAM for Android and Windows.
| +|Additional software|
  • A third-party telephony or VoIP app such as Skype is required for placing calls from [!INCLUDE[prodshort](../developer/includes/prodshort.md)].
  • A third-party email program such as Outlook is required for sending emails from [!INCLUDE[prodshort](../developer/includes/prodshort.md)].
  • Microsoft Office 2019, Office 2016, or Office 365 is required for sending data to Microsoft Excel or to Microsoft Word.
| +|Additional information|
  • Device diagonal screen size 7" for tablets.
  • Screen resolution 960 × 510 for tablets.
  • Device diagonal screen size 4" for phones.
  • Screen resolution 854 x 480 for phones.
| + +### AL Development Requirements + +The following table shows the minimum system requirements for customizing or extending [!INCLUDE[prodshort](../developer/includes/prodshort.md)] using the AL language in Visual Studio Code. + +||| +|-----|-----| +|Supported operating systems|
  • Window Server 2016.
  • Windows 10 - [supported versions](https://support.microsoft.com/help/13853/windows-lifecycle-fact-sheet).
| +|Required software|
  • [Visual Studio Code](https://code.visualstudio.com/Download)
  • [AL language extension](https://marketplace.visualstudio.com/items?itemName=ms-dynamics-smb.al)
| +|Hardware resources|
  • Hard disk space: 500 MB.
  • CPU: four cores minimum
  • Memory:
    16 GB for development only.
    16 GB for developing and locally deploying small extensions (<1000 objects>).
    32-64 GB for developing and locally deploying large extensions (>1000 objects).
| +|Reports|
  • For creating and editing RDL report layouts:
    • Report Builder for SQL Server 2016, or
    • Visual Studio 2017 with [Microsoft Rdlc Report Designer for Visual Studio](https://go.microsoft.com/fwlink/?linkid=857038) installed.
  • For creating and editing Word report layouts:
    • Word 2016 or later
| + +For more information, see [Getting Started with AL](../developer/devenv-get-started.md). + +## Server Components +### [!INCLUDE[prodshort](../developer/includes/prodshort.md)] Server Requirements + The following table shows the minimum system requirements for [!INCLUDE[server](../developer/includes/server.md)]. + +||| +|-----|-----| +|Supported operating systems|
  • Windows 10 Pro, Enterprise, or Education \(64-bit edition\).
  • Windows Server 2019 Standard, Essentials, or Datacenter.
  • Windows Server 2016 Standard, Essentials, or Datacenter.
.| +|Hardware resources|