c# - DocuSign 使用 .Net Core 3 连接 Webhook
问题描述
我在 .Net Core 3 Web API 中为DocuSign Connect创建一个 webhook,以调用并为我提供状态更新 + 来自我的应用程序创建的信封的签名文档。https://www.docusign.com/blog/dsdev-adding-webhooks-application上的 C# 示例对让我几乎实现目标非常有帮助。示例中的代码是:
[HttpPost("api/[controller]/ConnectWebHook")]
public void ConnectWebHook(HttpRequestMessage request)
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(request.Content.ReadAsStreamAsync().Result);
var mgr = new XmlNamespaceManager(xmldoc.NameTable);
mgr.AddNamespace("a", "http://www.docusign.net/API/3.0");
XmlNode envelopeStatus = xmldoc.SelectSingleNode("//a:EnvelopeStatus", mgr);
XmlNode envelopeId = envelopeStatus.SelectSingleNode("//a:EnvelopeID", mgr);
XmlNode status = envelopeStatus.SelectSingleNode("./a:Status", mgr);
var targetFileDirectory = @"\\my-network-share\";
if (envelopeId != null)
{
System.IO.File.WriteAllText($"{targetFileDirectory}{envelopeId.InnerText}_{status.InnerText}_.xml", xmldoc.OuterXml);
}
if (status.InnerText == "Completed")
{
// Loop through the DocumentPDFs element, storing each document.
XmlNode docs = xmldoc.SelectSingleNode("//a:DocumentPDFs", mgr);
foreach (XmlNode doc in docs.ChildNodes)
{
string documentName = doc.ChildNodes[0].InnerText; // pdf.SelectSingleNode("//a:Name", mgr).InnerText;
string documentId = doc.ChildNodes[2].InnerText; // pdf.SelectSingleNode("//a:DocumentID", mgr).InnerText;
string byteStr = doc.ChildNodes[1].InnerText; // pdf.SelectSingleNode("//a:PDFBytes", mgr).InnerText;
System.IO.File.WriteAllText($"{targetFileDirectory}{envelopeId.InnerText}_{documentId}_{documentName}", byteStr);
}
}
}
出于测试目的,我的 Web API 允许所有来源并通过 NGROK 向外界公开,并且我可以访问其他测试端点(GET 和 POST),但由于某种原因,当存在我的信封上值得通知的事件。
我可以在 DocuSign 管理门户日志中看到 Connect 调用了我的 webhook 但得到了远程服务器返回错误:(415)不支持的媒体类型。. 这导致我[FromBody]
像这样将属性添加到我的方法签名中,但是当我的 webhook 被 Connect 调用时,我仍然遇到同样的错误。
[HttpPost("api/[controller]/ConnectWebHook")]
public void ConnectWebHook([FromBody] HttpRequestMessage request)
{
// ... rest of the method was unchanged, removed for brevity
}
我以前从未使用HttpRequestMessage
过,但它看起来很简单。我在 DocuSign 管理门户日志中注意到 Connect 尝试发送到 webhook 的数据只是 XML。我可以尝试更改 webhook 的签名以寻找 anXmlDocument
而不是 anHttpRequestMessage
但我不确定我会错过什么,如果有的话。
最近有没有其他人通过 webhook 与 Connect 集成?你能够为你完成这项HttpRequestMessage
工作吗?
于 2019 年 10 月 18 日添加:
DocuSign 提到内容类型是 XML。这是内容的样子:
<DocuSignEnvelopeInformation
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.docusign.net/API/3.0">
<EnvelopeStatus>...</EnvelopeStatus>
<DocumentPDFs>...</DocumentPDFs>
</DocuSignEnvelopeInformation>
我已经添加AddXmlSerializerFormatters()
到ConfigureServices
. 这是 .Net Core 3,我必须像按照https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=那样Startup.cs
设置它视觉工作室。services.AddControllers().AddXmlSerializerFormatters()
services.AddMVC().AddXmlSerializerFormatters()
随着这种变化,我现在尝试[FromForm]
像这样使用并且我的 webhook被击中,但输入参数基本上是空的...... :request
request.Content = null
[HttpPost("api/[controller]/ConnectWebHook")]
public void ConnectWebHook([FromForm] HttpRequestMessage request)
{
// ... rest of the method was unchanged, removed for brevity
}
由于请求是从 DocuSign Connect 发送的,因此我无法控制标头/格式/内容。据我所知,他们没有提交 XML 对象,而不是表单,所以[FromForm]
可能不是要走的路。
解决方案
该链接示例不适用于 .net 核心。HttpRequestMessage
不再是 asp.net-core 框架中的一等公民,将被视为普通模型。
只需直接从请求的正文中提取内容,其余内容应该与示例中的内容相同。
[HttpPost("api/[controller]/ConnectWebHook")]
public IActionResult ConnectWebHook() {
Stream stream = Request.Body;
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(stream);
var mgr = new XmlNamespaceManager(xmldoc.NameTable);
mgr.AddNamespace("a", "http://www.docusign.net/API/3.0");
XmlNode envelopeStatus = xmldoc.SelectSingleNode("//a:EnvelopeStatus", mgr);
XmlNode envelopeId = envelopeStatus.SelectSingleNode("//a:EnvelopeID", mgr);
XmlNode status = envelopeStatus.SelectSingleNode("./a:Status", mgr);
var targetFileDirectory = @"\\my-network-share\";
if (envelopeId != null) {
System.IO.File.WriteAllText($"{targetFileDirectory}{envelopeId.InnerText}_{status.InnerText}_.xml", xmldoc.OuterXml);
}
if (status.InnerText == "Completed") {
// Loop through the DocumentPDFs element, storing each document.
XmlNode docs = xmldoc.SelectSingleNode("//a:DocumentPDFs", mgr);
foreach (XmlNode doc in docs.ChildNodes) {
string documentName = doc.ChildNodes[0].InnerText; // pdf.SelectSingleNode("//a:Name", mgr).InnerText;
string documentId = doc.ChildNodes[2].InnerText; // pdf.SelectSingleNode("//a:DocumentID", mgr).InnerText;
string byteStr = doc.ChildNodes[1].InnerText; // pdf.SelectSingleNode("//a:PDFBytes", mgr).InnerText;
System.IO.File.WriteAllText($"{targetFileDirectory}{envelopeId.InnerText}_{documentId}_{documentName}", byteStr);
}
}
return Ok();
}
推荐阅读
- python-3.x - 无法在 VSCode 上的 Jupyter 笔记本中使用 cx_Oracle 进行连接
- javascript - 如何解释 Observable.of(Math.random()) 总是返回相同的值?
- scala - Spark 2.3:减去数据帧但保留重复值(Scala)
- c# - 在 .NET 核心项目中使用来自 UWP api 的 Miracast 无法接收视频帧
- fpga - PCIe UIO 多 DWORD 访问问题
- ios - 在 swift 5 中为 UITextField 设置底部边框的问题
- css - 如果通过 CSS 满足条件,则在图像顶部添加文本
- javascript - JavaScript 书签(javascript:) 是否适用于 YouTube?
- gravity-forms-plugin - 基于重力形式中的数量的重复字段
- visual-studio-code - 无法让调试器在 VSCode 中处理 C 程序