首页 > 解决方案 > 如何在 C# [Open Invoice] 中发布具有两种不同文档类型和 HMAC 签名的 Multipart/mixed:boundary=”MIME-Boundary”

问题描述

作为与 Open Invoice 集成的一部分,API 需要传统的 Multipart/mixed:boundary=”MIME-Boundary” 请求标头。在 Internet 上使用此 C# Header 的文档非常少,包括 Microsoft 文档。

POST 请求中的两个文档包括一个 UTF-8 XML 字符串和一个 Base64 pdf 字符串。出站请求需要 HTTPRequestMessage 本身不支持的 Content-Type 标头(每个文档一个),因为它假定您将交付“文本/纯文本”请求。

Headers.Add() //设置Content-Type时抛出异常

Headers.TryAddWithoutValidation() //没有解决问题

此外,请求需要使用请求正文的 HMAC 哈希进行签名。

如何在 C# 中构建此请求?

标签: c#

解决方案


构建客户端

X509Certificate2 cert = new X509Certificate2(certificateName, certPassword);
        
var handler = new WebRequestHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(cert);
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(openInvoiceURL);

构建请求

        //Starting from byte[] for both files
        var xmlString = System.Text.Encoding.UTF8.GetString(xmlBytes);
        string pdf64 = Convert.ToBase64String(pdfBytes);
        string url = "/docp/supply-chain/v1/invoices";
        
        var multiPartContent = new MultipartContent("mixed", "_MIME-Boundary");

        var xmlHttpContent = new StringContent(xmlString);
        xmlHttpContent.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
        multiPartContent.Add(xmlHttpContent);

        var pdfHttpContent = new StringContent(pdf64);
        pdfHttpContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        pdfHttpContent.Headers.Add("content-transfer-encoding", "base64");
        pdfHttpContent.Headers.Add("Content-ID", pdfName);
        multiPartContent.Add(pdfHttpContent);
        
        var request = new HttpRequestMessage(HttpMethod.Post, url);
        request.Content = multiPartContent;
        request = AttachHMAC(request, secretKey);
        
        var response = client.SendAsync(request).Result;
        var responseString = response.Content.ReadAsStringAsync().Result;

签署请求正文(仅在 POST 上)

    private HttpRequestMessage AttachHMAC(HttpRequestMessage request, string secretKey)
    {
        var payload = string.Empty;
        if(request != null && request.Content != null)
        {
            payload = request.Content.ReadAsStringAsync().Result;
        }
        
        var hashMaker = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
        var payloadByteArray = Encoding.UTF8.GetBytes(payload);
        
        byte[] hash = hashMaker.ComputeHash(payloadByteArray);
        var base64Hash = Convert.ToBase64String(hash);

        request.Headers.Add("mac", base64Hash);
        return request;
    }

推荐阅读