前言
本文将以一个场景讲述如果在 Dynamics CRM App 中使用 “消息提醒(Notification)”,我将使用三种推送方式为用户创建消息提醒:
- Cloud Flow
- Client API
- Csharp(C#)
1.启用应用消息通知
Power Apps –> 点击菜单栏中 “App” –> 找到自己的应用 –> 点击 “三个点” –> 点击 “编辑”

Power Apps 界面
点击应用编辑页面上方的 Settings 按钮

Power Apps App Setting
点击 Features 选项卡 –> 启用 In App Notification –> 保存

启用消息提醒
如果一切顺利,可以在 Table 中看到 Notification 表:

Notification 表
2.创建消息提醒
方式1 使用 Cloud Flow
(1) 新建 Flow
打开解决方案 –> 新建 –> Automation –> Cloud flow –> Automated

Create Cloud Flow
输入一个有意义的 Flow 名称 –> 通过模糊搜索(输入:Dataverse) –> 选择 Create Cloud FlowWhen a row is added, modified or deleted
触发器 –> Create
(2) 配置 Flow
(1)配置 When a row is added, modified or deleted
触发器,然后点击 “+New Step”
- Change type:Modified
- Table name:Accounts
- Scope:Organization
- Select columns:ownerid

配置 “触发器”
(2)通过模糊搜索(输入:Dataverse),选择 Add a new row
操作

选择 “操作”
(3)配置 Add a new row
操作,然后点击保存按钮

配置 “操作”
- Table name:选择
Notifications
- Title:输入
Client assignment reminders
- Body:输入
Customer [变量:Account Name] has been assigned to you, please contact the customer in time.
- Expiry (seconds):输入
1200
- IconType:选择
Success
- Owner (Owners):输入
/systemusers(变量: Owner(Value))
- Data:输入下面的 Json ,其中 entityLigicalName 输入
account
, 和RecordId
需要替换
{
"actions": [
{
"title": "Open Account record",
"data":
{
"url": "?pagetype=entityrecord&etn=account&id=变量:Account",
"navigationTarget": "newWindow"
}
}
]
}
(3) 测试 Flow
打开一条客户记录,将这条客户记录分派给自己。

将客户记录分派给自己
如果一切顺利的话,你将在右上角看到弹出消息提醒:

右上角弹出消息提醒
点击右上角菜单栏中的小铃铛,可以展开消息提醒:

展开消息提醒
同时,用户在 Power Apps 移动端的应用中,一样能看到消息提醒:

在 Power Apps 移动端的应用中看到的消息提醒
方式2 使用 Client API
- 在客户表单添加 Example In-App Notification 按钮
- 点击按钮后创建消息提醒
(1) 编写 JavaScript 代码
这是本次使用的 JavaScript 代码:
/**
* Example code ...
*/
'use strict';
if (Gdh === undefined) { var Gdh = {}; }
if (Gdh.D365 === undefined) { Gdh.D365 = {}; }
if (Gdh.D365.Account === undefined) { Gdh.D365.Account = {}; }
(function () {
this.formOnLoad = function (executionContext) {
//var formContext = executionContext.getFormContext();
}
this.formOnSave = function () {
Xrm.Navigation.openAlertDialog({ text: "Record saved." });
}
this.ExampleCallAppNotification = function (executionContext) {
var formContext = executionContext;
var currentUserID = Xrm.Utility.getGlobalContext().userSettings.userId.replace("{", "").replace("}", "");
var accountName = formContext.getAttribute("name").getValue();
var sBody = `Customer [**${accountName}**] has been assigned to you, please contact the customer in time.`;
var currentRecordId = formContext.data.entity.getId().replace("{", "").replace("}", "");
var url = `?pagetype=entityrecord&etn=account&id=${currentRecordId}`;
var tData = {
"@odata.type": "Microsoft.Dynamics.CRM.expando",
"actions@odata.type": "#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "Open Account record",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "url",
"url": url,
"navigationTarget": "newWindow"
}
}
]
}
var SendAppNotificationRequest = new this.SendAppNotificationRequest(
"Client assignment reminders",
`/systemusers(${currentUserID})`,
sBody,
200000000,
100000001,
200000000,
null,
null,
tData
);
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
});
}
this.SendAppNotificationRequest = function (
title,
recipient,
body,
priority,
iconType,
toastType,
expiry,
overrideContent,
actions) {
this.Title = title;
this.Recipient = recipient;
this.Body = body;
this.Priority = priority;
this.IconType = iconType;
this.ToastType = toastType;
this.Expiry = expiry;
this.OverrideContent = overrideContent;
this.Actions = actions;
};
this.SendAppNotificationRequest.prototype.getMetadata = function () {
return {
boundParameter: null,
parameterTypes: {
"Title": {
"typeName": "Edm.String",
"structuralProperty": 1
},
"Recipient": {
"typeName": "mscrm.systemuser",
"structuralProperty": 5
},
"Body": {
"typeName": "Edm.String",
"structuralProperty": 1
},
"Priority": {
"typeName": "Edm.Int",
"structuralProperty": 1
},
"IconType": {
"typeName": "Edm.Int",
"structuralProperty": 1
},
"ToastType": {
"typeName": "Edm.Int",
"structuralProperty": 1
},
"Expiry": {
"typeName": "Edm.Int",
"structuralProperty": 1
},
"OverrideContent": {
"typeName": "mscrm.expando",
"structuralProperty": 5
},
"Actions": {
"typeName": "mscrm.expando",
"structuralProperty": 5
},
},
operationType: 0,
operationName: "SendAppNotification",
}
}
}).call(Gdh.D365.Account);
(2) 代码上传为网络资源

代码上传为网络资源
(3) 添加按钮
打开 解决方案 –> 选择 Account –> 选择 Commands –> 选择 New command

添加按钮-01
点击 “+New”

添加按钮-02
填写按钮信息 –> 点击 Save and Publish
- Label:Example In-App Notification
- Action:Run JavaScript
- Library:gdh_/Account/Account.js | Gdh.D365.Account.ExampleCallAppNotification
- Parameter:PrimaryControl

添加按钮-03
(4) 测试
点击 Example In-App Notification 按钮后,你将在右上角看到弹出消息提醒:

悬浮出消息提醒
方式3 使用 Csharp
在控制台应用程序中添加如下代码,然后运行。
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Tooling.Connector;
using System;
using System.Configuration;
namespace Blog.D365.Conn.ConsoleApp
{
public class Program
{
static void Main(string[] args)
{
string connectionStr = ConfigurationManager.ConnectionStrings["Dev-Office365"].ConnectionString;
CrmServiceClient client = new CrmServiceClient(connectionStr);
if (client.IsReady)
{
IOrganizationService orgService = client;
NotificationService notificationService = new NotificationService(orgService);
notificationService.CreateAppNotification(
"Client assignment reminders -- Form Console",
new Guid("DDF2C431-A1DF-EE11-904D-0017FA06CFC8"),
"Customer [**Bright Design Studio**] has been assigned to you, please contact the customer in time.",
new OptionSetValue(100000001),
new OptionSetValue(200000000),
"?pagetype=entityrecord&etn=account&id=23956352-CEBA-EF11-B8E8-0017FA0527B1",
"newWindow"
);
}
else
{
throw new Exception(client.LastCrmError);
}
}
}
public class NotificationService
{
private readonly IOrganizationService _orgService;
public NotificationService(IOrganizationService orgService)
{
_orgService = orgService;
}
public void CreateAppNotification(
string title,
Guid recipientId,
string body,
OptionSetValue iconType,
OptionSetValue toastType,
string url,
string navigationTarget,
Entity overrideContent = null)
{
OrganizationRequest request = new OrganizationRequest
{
RequestName = "SendAppNotification",
Parameters = new ParameterCollection
{
["Title"] = title,
["Recipient"] = new EntityReference("systemuser", recipientId),
["Body"] = body,
["IconType"] = iconType,
["ToastType"] = toastType,
["Actions"] = new Entity
{
Attributes = {
["actions"] = new EntityCollection
{
Entities = {
new Entity
{
Attributes = {
["title"] = "Open Account record",
["data"] = new Entity
{
Attributes = {
["type"] = "url",
["url"] = url,
["navigationTarget"] = navigationTarget
}
}
}
}
}
}
}
},
["OverrideContent"] = overrideContent,
}
};
_orgService.Execute(request);
}
}
}

在控制台运行执行后看到的效果
3.常用属性
(1) ToastType
ToastType | 值 | 描述 |
---|---|---|
Timed | 200000000 | 消息提醒会短暂出现(默认为 4 秒),然后消失 |
Hidden | 200000001 | 消息提醒不会弹出,只有通过点击右上角的 “铃铛(消息中心)” 才能看到 |
(2) IconType 选项
IconType | 值 |
---|---|
Info | 100000000 |
Success | 100000001 |
Failure | 100000002 |
Warning | 100000003 |
Mention | 100000004 |
Custom | 100000005 |

IconType 选项
(3) 设置通知优先级
通过设置 Priority
来改变通知在通知中心的显示顺序
Priority | 值 |
---|---|
Normal 普通的 | 200000000 |
High 高的 | 200000001 |
Normal
。通知中心中的通知按优先级和创建日期降序排列。高优先级通知显示在通知中心列表顶部。(4) Notification actions
this.ExampleCallAppNotification = function (executionContext) {
// ...
var url = `?pagetype=entityrecord&etn=account&id=${currentRecordId}`;
var tData = {
"@odata.type": "Microsoft.Dynamics.CRM.expando",
"actions@odata.type": "#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "Open Account record",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "url",
"url": url,
"navigationTarget": "newWindow"
}
}
]
}
// ...
}
actions
支持三种操作类型:
Priority | 值 |
---|---|
Normal 普通的 | 200000000 |
High 高的 | 200000001 |
(5) 定义 URL 动作
URL 操作类型支持从应用通知上的操作导航到定义的 URL。有以下参数:
url
:选择操作时要打开网址的 URLnavigationTarget
:控制导航链接打开的位置dialog
,Dialog 形式打开inline
,默认;在当前页面中打开newWindow
,新浏览器选项卡中打开
this.ExampleCallAppNotification = function (executionContext) {
// ...
var url = `?pagetype=entityrecord&etn=account&id=${currentRecordId}`;
var tData = {
"@odata.type": "Microsoft.Dynamics.CRM.expando",
"actions@odata.type": "#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "Open Account record",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "url",
"url": url,
"navigationTarget": "newWindow"
}
}
]
}
// ...
}
Title 和 Body 使用 Markdown
OverrideContent
属性中进行重写(覆盖)Title 和 Body 。样式 | Markdown |
---|---|
粗体 | **Bold** |
斜体 | _Italic_ |
无序列表 | - Item 1\r- Item 2\r- Item 3 |
有序列表 | 1. Green\r2. Orange\r3. Blue |
超链接 | [Title](url) |
例如重写消息提醒的 Title
,然后为 Body
中的客户名称添加超链接,还将 “please contact the customer in time” 设置为斜体,修改的代码如下。
- Client API
this.ExampleCallAppNotification = function (executionContext) {
var formContext = executionContext;
var currentUserID = Xrm.Utility.getGlobalContext().userSettings.userId.replace("{", "").replace("}", "");
var accountName = formContext.getAttribute("name").getValue();
var sBody = `Customer [**${accountName}**] has been assigned to you, please contact the customer in time.`;
var currentRecordId = formContext.data.entity.getId().replace("{", "").replace("}", "");
var url = `?pagetype=entityrecord&etn=account&id=${currentRecordId}`;
var tData = {
"@odata.type": "Microsoft.Dynamics.CRM.expando",
"actions@odata.type": "#Collection(Microsoft.Dynamics.CRM.expando)",
"actions": [
{
"title": "Open Account record",
"data": {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"type": "url",
"url": url,
"navigationTarget": "newWindow"
}
}
]
};
var overrideContent = {
"@odata.type": "#Microsoft.Dynamics.CRM.expando",
"title": "**(Override)Client assignment reminders**",
"body": `Customer [${accountName}](${url}) has been assigned to you, _please contact the customer in time_.`
};
var SendAppNotificationRequest = new this.SendAppNotificationRequest(
"Client assignment reminders",
`/systemusers(${currentUserID})`,
sBody,
200000000,
100000001,
200000000,
null,
overrideContent,
tData
);
Xrm.WebApi.online.execute(SendAppNotificationRequest).then(function (response) {
if (response.ok) {
console.log("Status: %s %s", response.status, response.statusText);
return response.json();
}
})
.then(function (responseBody) {
console.log("Response Body: %s", responseBody.NotificationId);
})
.catch(function (error) {
console.log(error.message);
});
};
效果如下:

IconType 重写消息提醒的 Title、Body
需要注意
1.应用内通知功能,用户需要权限才能接收通知并向自己或其他用户发送通知
表名 | 所需权限 | 备注 |
---|---|---|
Send In-App Notification | 组织 | |
Notification | 创建,读取,写入,追加,追加到 | 如果是通过创建 Notification 记录的形式来发送消息通知,才需要配置这张表的权限 |
2.关于存储。Notification 表使用的是数据库存储容量,需要考虑 “通知量” 和 “设置过期”,建议合理的设置 Expiry
。
3.通知是特定用户的。每条通知仅针对单个用户,在发送通知时标识为收件人。不支持向团队发送通知,如果需要向多个用户发送通知,则必须为每个用户创建通知。
感谢您的耐心阅读!来选个表情,或者留个评论吧!