从 MS CRM 插件(沙盒)向 Azure 服务总线发送自定义消息
Send custom messages to Azure Service Bus from MS CRM Plugins (Sandbox)
我知道我可以在 MS CRM 中注册一个新的 "Service Endpoint" 并使用它向 Azure 服务总线发送消息,但这...并不是我真正想要的。上面的方法最终发送了一个序列化的 RemoteExecutionContext
.
就我而言,我想完全控制服务总线消息将包含的内容。这意味着序列化我自己的 类.
我已经尝试使用 WindowsAzure.ServiceBus
nugget(和 ILmerging 新 DLL),但这只适用于非沙盒设置(内部部署 CRM),但我也想要我的解决方案在 CRM Online 中工作。尝试在 CRM Online 中使用相同的代码然后尝试创建 TopicClient
时会引发错误:
System.Security.SecurityException: That assembly does not allow partially trusted callers
有没有办法解决上述问题?
对于 CRM Online,您可以将消息逻辑 conversion/processing 置于沙盒之外。它将需要一些外部计算。考虑到您已经在线使用 CRM,这应该不是问题。
您可以采用的一种方法是将 RemoteExecutionContext
构建的 CRM 转换为您想要的任何类型。有一个sample of how to integrate Dynamics 365 with NServiceBus, which take this approach as well. The compute I was referring to would be the equivalent of the CRMAdapterEndpoint
endpoint from the sample. The endpoint is using a Mapper
object to convert JSON serialized RemoteExecutionContext
to custom types, ContactCreate
and ContactUpdate
。那会让你实现你想要的。
我找到了一种与 Sandboxed MS CRM 兼容的方法。
想法是使用 Azure REST 端点向其发送消息。验证和使用相当容易......至少如果你有一个工作示例,我能够找到它 here.
这是一个相当不错的样本,尽管有点乱。尽管如此,它还是展示了如何让基础知识发挥作用,即身份验证和实际调用。
(小注:根据示例从 ASB 读取主题消息对我来说工作不可靠 - 它会工作一次然后直到授权密钥超时才工作......这并没有打扰我,因为我只需要发送消息,但如果这是您需要的功能,那么这可能不是那么简单。)
我知道这是一个老问题,但我最近不得不做类似的事情,我使用 SharedVariable Collection 将额外的细节和参数传递给 ServiceBus。
这是一个例子:
context.SharedVariables.Add("AttachmentType", attachmentType);
这是一种无需额外 类 且无需使用 ILMerge 即可执行此操作的方法。我在 CRM 在线版本 9.1.0.646 (Dynamics 365 Customer Engagement)
中验证了这一点
您的插件项目将需要以下引用和使用语句。
参考文献:System.Net、System.Net.Http
Usings: System.Net, System.Net.Http, System.Security.Cryptography, System.Globalization
在此示例代码中,我建立了一个名为 json 的字符串变量,它是我想要 post 的 JSON 消息。然后下面的代码将发送消息。
string asbUri =
"https://<azurenamespace>.servicebus.windows.net/<topicname>/messages";
TimeSpan ts = new TimeSpan(0, 0, 90);
string sasToken = GetSASToken("sb://<azurenamespace>.servicebus.windows.net", "
<nameofSASkey>", "<SASKeyValue>", ts);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", sasToken);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, asbUri)
{
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
HttpResponseMessage response = client.SendAsync(request).Result;
private static string GetExpiry(TimeSpan ttl)
{
TimeSpan expirySinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1) + ttl;
return Convert.ToString((int)expirySinceEpoch.TotalSeconds);
}
public static string GetSASToken(string resourceUri, string keyName, string key,
TimeSpan ttl)
{
var expiry = GetExpiry(ttl);
//string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
//NOTE: UrlEncode is not supported in CRM, use System.Uri.EscapeDataString instead
string stringToSign = Uri.EscapeDataString(resourceUri).ToLowerInvariant() + "\n"
+ expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature =
Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature
sr={0}&sig={1}&se={2}&skn={3}",
Uri.EscapeDataString(resourceUri).ToLowerInvariant(),
Uri.EscapeDataString(signature), expiry, keyName);
return sasToken;
}
我知道我可以在 MS CRM 中注册一个新的 "Service Endpoint" 并使用它向 Azure 服务总线发送消息,但这...并不是我真正想要的。上面的方法最终发送了一个序列化的 RemoteExecutionContext
.
就我而言,我想完全控制服务总线消息将包含的内容。这意味着序列化我自己的 类.
我已经尝试使用 WindowsAzure.ServiceBus
nugget(和 ILmerging 新 DLL),但这只适用于非沙盒设置(内部部署 CRM),但我也想要我的解决方案在 CRM Online 中工作。尝试在 CRM Online 中使用相同的代码然后尝试创建 TopicClient
时会引发错误:
System.Security.SecurityException: That assembly does not allow partially trusted callers
有没有办法解决上述问题?
对于 CRM Online,您可以将消息逻辑 conversion/processing 置于沙盒之外。它将需要一些外部计算。考虑到您已经在线使用 CRM,这应该不是问题。
您可以采用的一种方法是将 RemoteExecutionContext
构建的 CRM 转换为您想要的任何类型。有一个sample of how to integrate Dynamics 365 with NServiceBus, which take this approach as well. The compute I was referring to would be the equivalent of the CRMAdapterEndpoint
endpoint from the sample. The endpoint is using a Mapper
object to convert JSON serialized RemoteExecutionContext
to custom types, ContactCreate
and ContactUpdate
。那会让你实现你想要的。
我找到了一种与 Sandboxed MS CRM 兼容的方法。
想法是使用 Azure REST 端点向其发送消息。验证和使用相当容易......至少如果你有一个工作示例,我能够找到它 here.
这是一个相当不错的样本,尽管有点乱。尽管如此,它还是展示了如何让基础知识发挥作用,即身份验证和实际调用。
(小注:根据示例从 ASB 读取主题消息对我来说工作不可靠 - 它会工作一次然后直到授权密钥超时才工作......这并没有打扰我,因为我只需要发送消息,但如果这是您需要的功能,那么这可能不是那么简单。)
我知道这是一个老问题,但我最近不得不做类似的事情,我使用 SharedVariable Collection 将额外的细节和参数传递给 ServiceBus。
这是一个例子:
context.SharedVariables.Add("AttachmentType", attachmentType);
这是一种无需额外 类 且无需使用 ILMerge 即可执行此操作的方法。我在 CRM 在线版本 9.1.0.646 (Dynamics 365 Customer Engagement)
中验证了这一点您的插件项目将需要以下引用和使用语句。
参考文献:System.Net、System.Net.Http Usings: System.Net, System.Net.Http, System.Security.Cryptography, System.Globalization
在此示例代码中,我建立了一个名为 json 的字符串变量,它是我想要 post 的 JSON 消息。然后下面的代码将发送消息。
string asbUri =
"https://<azurenamespace>.servicebus.windows.net/<topicname>/messages";
TimeSpan ts = new TimeSpan(0, 0, 90);
string sasToken = GetSASToken("sb://<azurenamespace>.servicebus.windows.net", "
<nameofSASkey>", "<SASKeyValue>", ts);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", sasToken);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, asbUri)
{
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
HttpResponseMessage response = client.SendAsync(request).Result;
private static string GetExpiry(TimeSpan ttl)
{
TimeSpan expirySinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1) + ttl;
return Convert.ToString((int)expirySinceEpoch.TotalSeconds);
}
public static string GetSASToken(string resourceUri, string keyName, string key,
TimeSpan ttl)
{
var expiry = GetExpiry(ttl);
//string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
//NOTE: UrlEncode is not supported in CRM, use System.Uri.EscapeDataString instead
string stringToSign = Uri.EscapeDataString(resourceUri).ToLowerInvariant() + "\n"
+ expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature =
Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature
sr={0}&sig={1}&se={2}&skn={3}",
Uri.EscapeDataString(resourceUri).ToLowerInvariant(),
Uri.EscapeDataString(signature), expiry, keyName);
return sasToken;
}