开发者

WCF: (MTOM) is there any way to change the scheme used in xop:Content reference uris generated by WCF?

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:3f3ec388-8cd9-47aa-a603-fb1bc17935b8@example.jaxws.sun.com"

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:3f3ec388-8cd9-47aa-a603-fb1bc17935b8@example.jaxws.sun.com"/>
</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


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.


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.


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:3f3ec388-8cd9-47aa-a603-fb1bc17935b8@example.jaxws.sun.com"/>
</Data>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜