WCF MTOM附件如何设置内容类型

时间:2018-11-24 14:08:08

标签: c# .net wcf content-type mtom

我需要为MTOM配置的绑定中的二进制部分设置特定的内容类型(application / pdf)。

配置或代码中是否可以设置内容类型?对于文件部分,它始终为“ Content-Type:应用程序/八位字节流”

配置:

<binding name="FileTransferServicesBinding"
 closeTimeout="00:01:00" openTimeout="00:01:00"
 receiveTimeout="00:10:00" sendTimeout="00:01:00"
 messageEncoding="Mtom" transferMode="Buffered"
 maxBufferSize="67108864" maxReceivedMessageSize="67108864">
 <security mode="Transport" />
</binding>

当前发送到该服务的内容。该文件的多部分标头应为application / pdf,而不是application / octetstream

POST https://somewebservice HTTP/1.1
MIME-Version: 1.0
Authorization: Basic authhash
SOAPAction: ""
Host: webservicehost
Content-Length: 24517
Expect: 100-continue
Accept-Encoding: gzip, deflate


--uuid:b8366a06-3ecc-4bc4-9809-8c87ad459981+id=1
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header>[The soapmessageitself]</s:Envelope>
--uuid:b8366a06-3ecc-4bc4-9809-8c87ad459981+id=1
Content-ID: <http://tempuri.org/1/636787311873257476>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream // This must be application/pdf

%PDF-1.4
%    
1 0 obj
<</Type /Catalog/Pages 2 0 R>> ...

2 个答案:

答案 0 :(得分:0)

我不得不猜测您正在编码对请求的响应。如果是这样,您只需将内容类型标头添加到外发邮件中:

OperationContext
  .Current
  .OutgoingMessageHeaders
  .Add ("Content-Type", "application/pdf" );

不确定100%,但是您可能需要首先清除所有现有的传出Content-Type标头。我认为您的邮件经过MTOM编码并不重要。从理论上讲这是透明的。

还...只是问...当流式传输的消息占用的内存少得多时,为什么允许64MB缓冲的消息进行传输...并且速度可能会一样快或更快?您可以保证在高负载的服务中获得更好的性能。

更新

如果您很幸运地使用了Web api类型的绑定(WebHttpBinding)...,您可以轻松地流式传输您的内容,并指定内容类型。它与我在上面的答案中输入的内容没有什么不同,但是正如您回答的那样,那些标头放到错误的位置。

它应该是:

WebOperationContext
  .Current
  .OutgoingResponse
  .ContentType = "application/pdf";

有一篇很棒的文章/示例here,它以与您的目标相一致的方式完全发展了这个想法。

如果要绑定到较旧的肥皂绑定,则可能需要编写一个自定义消息编码器。该技术非常简单(如果很乏味)。基本思想是,您可以控制以适合您需要的方式编写邮件正文。

编码器本身是微不足道的。围绕它的样板将是乏味的部分。定制编码器从抽象MessageEncoder派生。重要的事情是重写ContentTypeMediaTypeMessageVersion属性以及ReadMessageWriteMessage方法。 ReadMessageWriteMessage方法有多种处理流和缓冲消息的方法。

丑陋的部分是部署编码器必须编写的样板。您已经建立了一个编码器工厂和一个自定义绑定元素。不是很糟糕,但是很吵。在示例代码包here中有几个完整的蜡球示例(包括工厂和绑定元素支持)……可以为您节省一些时间。

答案 1 :(得分:0)

随着时间的推移,我通过手动构建Soap Call解决了这个问题。由于对此问题有很多悬赏,因此我将标记答案相同但使用WCF库作为正确答案的答案。下面的代码示例以“ byteContent.Headers.Add(” Content-Type“,” application / pdf; name = test.pdf“);”开头我需要对WCF做些什么

static HttpClient client;
static object mutex = new object();
static HttpClient Client
{
    get
    {
        if (client == null)
        {
            lock (mutex)
            {
                if (client == null)
                {
                    client = new HttpClient();
                    client.DefaultRequestHeaders.Add("MIME-Version", "1.0");
                    client.DefaultRequestHeaders.Add("SOAPAction", "\"\"");
                    client.DefaultRequestHeaders.ConnectionClose = true;
                    client.DefaultRequestHeaders.ExpectContinue = false;
                    client.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(Username + ":" + Password)));
                }
            }
        }

        return client;
    }
}

public static TResponse Send<TResponse>(string endpoint, string payload, byte[] file)
{
    string boundary = Guid.NewGuid().ToString("N");
    MultipartContent multipart = new MultipartContent("related", boundary);

    multipart.Headers.Remove("Content-Type");
    multipart.Headers.TryAddWithoutValidation("Content-Type", "multipart/related; boundary=\"" + boundary + "\"");
    multipart.Add(new StringContent(payload, Encoding.UTF8, "text/xml"));

    ByteArrayContent byteContent = new ByteArrayContent(file);
    byteContent.Headers.Remove("Content-Type");
    byteContent.Headers.Add("Content-Type", "application/pdf; name=test.pdf");
    byteContent.Headers.Add("Content-Transfer-Encoding", "binary");
    byteContent.Headers.Add("Content-ID", "<test.pdf>");
    byteContent.Headers.Add("Content-Disposition", "attachment; name=\"test.pdf\"; filename=\"test.pdf\"");

    multipart.Add(byteContent);

    var result = Client.PostAsync(endpoint, multipart).Result;
    result.EnsureSuccessStatusCode();

    var resultString = result.Content.ReadAsStringAsync().Result;
    TResponse resultTyped = XmlHelper.ToObject<TResponse>(resultString);
    return resultTyped;
}