DocuSign连接Webhook与.Net Core 3

时间:2019-10-17 20:25:44

标签: c# .net-core docusignapi webhooks

我正在.Net Core 3 Web API中创建一个Webhook,用于 DocuSign Connect ,以从我的应用程序创建的信封中调用并提供状态更新+签名的文档。 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]属性添加到方法签名中,就像这样,但是当Connect调用Webhook时,仍然出现相同的错误。

[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的签名,以寻找XmlDocument而不是HttpRequestMessage,但是我不确定会丢失什么(如果有的话)。

最近有没有其他人通过网络挂钩与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中的Startup.cs方法中。这是.Net Core 3,我必须像services.AddControllers().AddXmlSerializerFormatters()那样设置它,而不是像https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio那样设置services.AddMVC().AddXmlSerializerFormatters()

有了这一更改,我现在尝试像这样使用[FromForm]并击中我的Webhook IS ,但是request输入参数实际上是空的... {{ 1}}:

request.Content = null

由于请求是从DocuSign Connect发送的,所以我无法控制标题/格式/内容。据我所知,他们没有提交XML对象,也没有提交表单,因此[HttpPost("api/[controller]/ConnectWebHook")] public void ConnectWebHook([FromForm] HttpRequestMessage request) { // ... rest of the method was unchanged, removed for brevity } 可能不是解决之道。

1 个答案:

答案 0 :(得分:1)

该链接示例不适用于.net核心。 HttpRequestMessage不再是asp.net核心框架中的头等公民,而将被视为普通模型。

仅从请求的正文中直接提取内容,其余内容应与示例中的内容相同。

[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();
}