WCF:(MTOM)有什么方法可以更改 xop:WCF 生成的内容引用 uri 中使用的方案吗?

发布于 2024-08-21 16:01:16 字数 2546 浏览 3 评论 0原文

在处理流式 MTOM 请求时,WCF 使用 http://tempuri/1/number 作为 Content-ID uri 引用。

有什么方法可以强制 WCF 对 xop:Include 使用不同的 Content-ID 引用吗?

问题背景:

我正在为支持 MTOM 的 jax ws java web 服务构建一个 .NET 客户端,该服务处理流式大数据上传。我手工制作了服务和数据联系人(WSDL 生成的合约不正确并且不允许流式传输)。

问题是 Web 服务 (jax ws) 未收到包含数据的请求正文。

它接收在标头中传输的数据。

我们已经为 ws 构建了一个 java 客户端 - 这个可以工作。

我捕获并比较了从 java 和 wcf 发出请求时的 HTTP 流量,唯一的区别在于发布多部分数据时如何生成 Content-ID 引用:

  • WCF 使用 http://tempuri/1 /... 产生编码值的 Content-ID 引用,例如 href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928"

  • Java 客户端使用“电子邮件样式”uri,例如 href="cid:[电子邮件受保护]"

这些在以下 xop-includes 中产生(数据是唯一的肥皂体中的元素)(XOP 包括规范


//WCF:
<Data>
   <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928" />
</Data>

//JAVA:
<Data>
    <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:[email protected]"/>
</Data>

)在多部分数据中,内容由未编码的 Content-ID 引用:

--uuid:7e166bb7-042f-4ba3-b6ef-98fbbc21244b+id=1
Content-ID: <http://tempuri.org/1/634019957020047928>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream

我猜想 jax Web 服务框架中可能存在错误,并且它无法识别 WCF 生成的+urlencoded 内容 - ID uri 引用。

有什么方法可以强制 WCF 对 xop:Include 使用不同的 Content-ID 引用吗?


编辑:我找到了具有GenerateUriForMimePart 方法的 XmlMtomWriter,该方法用于生成 Content-ID 。

public static string GenerateUriForMimePart(int index)
{
    return string.Format(CultureInfo.InvariantCulture, 
"http://tempuri.org/{0}/{1}", new object[] { index, DateTime.Now.Ticks });
}

ID 生成似乎无论如何都不可重写。

这里描述了类似的问题,提供的答案没有帮助: http://social.msdn.microsoft.com/Forums/en/wcf/thread/f90affbd-f431-4602-a81d-cc66c049e351

WCF uses http://tempuri/1/number for Content-ID uri references when handling streamed MTOM requests.

Is there any way how to force WCF to use a different Content-ID references for the xop:Include?

Background of the problem:

I am building a .NET client for MTOM enabled jax ws java web service that handles streamed large data uploads. I have hand crafted the service and data contacts (the WSDL generated contracts were not correct and did not allow streaming).

The problem is that the web service (jax ws) does not receive the request body containing the data.

It receives the data that is transferred in headers.

We have built a java client for the ws - this one works.

I have captured and compared the HTTP traffic when issuing requests from java and wcf, and the only difference is in how Content-ID reference is generated when posting the multipart data:

  • WCF uses http://tempuri/1/... Content-ID references which yield in encoded value, like href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928"

  • Java client uses "email-style" uris, like href="cid:[email protected]"

These yield in the following xop-includes (Data is the only element in the soap body) (XOP includes specification)


//WCF:
<Data>
   <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928" />
</Data>

//JAVA:
<Data>
    <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:[email protected]"/>
</Data>

later on, in the multipart data, the content is referred to by unencoded Content-ID:

--uuid:7e166bb7-042f-4ba3-b6ef-98fbbc21244b+id=1
Content-ID: <http://tempuri.org/1/634019957020047928>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream

I guess there may be a bug in the jax web service framework and it is not recognizing WCF-generated+urlencoded Content-ID uri references.

Is there any way how to force WCF to use a different Content-ID references for the xop:Include?


EDIT: I have found the XmlMtomWriter which has the GenerateUriForMimePart method, this is used to generate Content-IDs.

public static string GenerateUriForMimePart(int index)
{
    return string.Format(CultureInfo.InvariantCulture, 
"http://tempuri.org/{0}/{1}", new object[] { index, DateTime.Now.Ticks });
}

It does not seem that the ID generation is in any way overridable.

A similar issue is described here, the answer provided does not help: http://social.msdn.microsoft.com/Forums/en/wcf/thread/f90affbd-f431-4602-a81d-cc66c049e351

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千秋岁 2024-08-28 16:01:16

经过长时间的调查后我对自己说:如果不重新实现整个 XmlMtomWriter 以及 WCF 中的其他相关层和关注点,就不可能实现 - 几乎 mtom 实现中涉及的所有内容都是内部的。

Asnwering to myself after long investigation: Not possible without reimplementing the whole XmlMtomWriter and other related layers and concerns in WCF - almost everything involved in the mtom implementation is internal.

開玄 2024-08-28 16:01:16

我知道这是一个老问题。但两天前我也遇到了同样的问题。

我找到了一种可行的方法,但它是一个非常非常肮脏的黑客(我知道。我想过不在这里发布它,但也许它会对某人有所帮助。)希望你不会因此责怪我。

ContentId 使用 CultureInfo.InvariantCulture 进行格式化。我没有找到用自定义 CultureInfo 替换它的官方方法。但在反思的帮助下,我让它运行起来。以下实现仅适用于.Net 4.0。

public class NoTempUriInvariantCultureInfo : CultureInfo, ICustomFormatter
{
   private static CultureInfo originalCulture;
   private static object originalCultureLock;
   private static int enableCounter;

   private NoTempUriInvariantCultureInfo(CultureInfo invariantCulture)
      : base(invariantCulture.Name)
   {
      originalCulture = invariantCulture;
   }

   public static void Enable()
   {
      if(originalCultureLock == null)
         originalCultureLock = new object();

      lock (originalCultureLock)
      {
         if (enableCounter == 0)
         {
            var mInvCultField = typeof (CultureInfo).GetField("s_InvariantCultureInfo", BindingFlags.NonPublic | BindingFlags.Static);
            mInvCultField.SetValue(null, new NoTempUriInvariantCultureInfo(CultureInfo.InvariantCulture));
         }
         enableCounter++;
      }
   }

   public static void Disable()
   {
      lock (originalCulture)
      {
         if (enableCounter == 0)
            return;

         enableCounter--;
         if (enableCounter == 0)
         {
            var mInvCultField = typeof (CultureInfo).GetField("s_InvariantCultureInfo", BindingFlags.NonPublic | BindingFlags.Static);
            mInvCultField.SetValue(null, NoTempUriInvariantCultureInfo.originalCulture);
         }
      }
   }

   public override object GetFormat(Type formatType)
   {
      var result = originalCulture.GetFormat(formatType);
      return result ?? this;
   }

   public string Format(string format, object arg, IFormatProvider formatProvider)
   {
      if (format == null)
         return System.Text.RegularExpressions.Regex.Replace(arg.ToString().Replace("http%3A%2F%2Ftempuri.org%2F1%2F", ""), "http[:][/][/]tempuri[.]org[/][0-9]+[/]*", "");
      return String.Format("{0:" + format + "}", arg);
   }
}

我仅在 WCF 调用之前启用我自己的“InvariantCulture”。

NoTempUriInvariantCultureInfo.Enable();
try
{
    // make your call
}
finally
{
    NoTempUriInvariantCultureInfo.Disable();
}

CultureInfo.InvariantCulture 是一个全局状态对象。启用我自己的 InvariantCulture 会影响所有其他线程。
再说一遍,这是一个肮脏的黑客行为。但它有效。

I know it is an old question. But I'm faced the same problem two days ago.

I found a way which works BUT it is a VERY VERY dirty hack (I know that. I thought about not publishing it here but perhaps it would help somebody.) Hopefully you will not blame me for that.

The ContentId is formatted with the use of CultureInfo.InvariantCulture. I didn't find an official way for replacing it with a custom CultureInfo. But with the help of reflection I got it running. The following implementation is only for .Net 4.0.

public class NoTempUriInvariantCultureInfo : CultureInfo, ICustomFormatter
{
   private static CultureInfo originalCulture;
   private static object originalCultureLock;
   private static int enableCounter;

   private NoTempUriInvariantCultureInfo(CultureInfo invariantCulture)
      : base(invariantCulture.Name)
   {
      originalCulture = invariantCulture;
   }

   public static void Enable()
   {
      if(originalCultureLock == null)
         originalCultureLock = new object();

      lock (originalCultureLock)
      {
         if (enableCounter == 0)
         {
            var mInvCultField = typeof (CultureInfo).GetField("s_InvariantCultureInfo", BindingFlags.NonPublic | BindingFlags.Static);
            mInvCultField.SetValue(null, new NoTempUriInvariantCultureInfo(CultureInfo.InvariantCulture));
         }
         enableCounter++;
      }
   }

   public static void Disable()
   {
      lock (originalCulture)
      {
         if (enableCounter == 0)
            return;

         enableCounter--;
         if (enableCounter == 0)
         {
            var mInvCultField = typeof (CultureInfo).GetField("s_InvariantCultureInfo", BindingFlags.NonPublic | BindingFlags.Static);
            mInvCultField.SetValue(null, NoTempUriInvariantCultureInfo.originalCulture);
         }
      }
   }

   public override object GetFormat(Type formatType)
   {
      var result = originalCulture.GetFormat(formatType);
      return result ?? this;
   }

   public string Format(string format, object arg, IFormatProvider formatProvider)
   {
      if (format == null)
         return System.Text.RegularExpressions.Regex.Replace(arg.ToString().Replace("http%3A%2F%2Ftempuri.org%2F1%2F", ""), "http[:][/][/]tempuri[.]org[/][0-9]+[/]*", "");
      return String.Format("{0:" + format + "}", arg);
   }
}

I enable my own "InvariantCulture" only before a WCF call.

NoTempUriInvariantCultureInfo.Enable();
try
{
    // make your call
}
finally
{
    NoTempUriInvariantCultureInfo.Disable();
}

CultureInfo.InvariantCulture is a global state object. Enabling my own InvariantCulture affects every other thread.
Again, it is a dirty hack. But it works.

听,心雨的声音 2024-08-28 16:01:16

这两个 XOP 都包含您指出的示例,这些示例是正确的并且根据 W3C 可以接受。我将它们分别称为 URL 格式和电子邮件格式。

我不是 JAVA 开发人员,但记得在与特定 JAVA Web 服务交互时遇到过类似的问题。我记得在某个特定的 JAVA 版本中存在一个错误,在他们(JAVA 开发人员)升级到下一个版本后,这个问题就消失了。我希望能为您提供更多详细信息,但当时,有足够多的问题需要我从电话那头解决,我很高兴缺陷日志上少了一项。

//WCF: using URL format
<Data>
   <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928" />
</Data>

//JAVA: using EMAIL format
<Data>
    <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:[email protected]"/>
</Data>

Both of the XOP includes samples that you indicated are correct and acceptable according to the W3C. I refer to them as the URL format and the Email format respectively.

I am not a JAVA developer, but recall a similiar problem when interfacing with a particular JAVA web service. I recall there being a bug in a particular JAVA release and after they (the JAVA developers) upgraded to the next release version, this issue simply went away. I wish I could provide you more details, but at the time, there were enough problems for me to address from my end of the wire and I was just glad to have one less item on the defect log.

//WCF: using URL format
<Data>
   <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928" />
</Data>

//JAVA: using EMAIL format
<Data>
    <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:[email protected]"/>
</Data>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文