首页 > 解决方案 > 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被击中,但输入参数基本上是空...... :requestrequest.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]可能不是要走的路。

标签: c#.net-coredocusignapiwebhooks

解决方案


该链接示例不适用于 .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();
}

推荐阅读