2010-02-17 21 views
10

WCF utilise http://tempuri/1/number pour les références uri Content-ID lors de la gestion des requêtes MTOM en streaming.WCF: (MTOM) existe-t-il un moyen de changer le schéma utilisé dans xop: uris de référence de contenu généré par WCF?

Existe-t-il un moyen de forcer WCF à utiliser des références Content-ID différentes pour le xop: Include?

Contexte du problème:

Je construis un client .NET pour le service JAX activé MMD ws java web qui gère ruisselait gros téléchargements de données. J'ai fabriqué à la main les contacts de service et de données (les contrats générés par WSDL n'étaient pas corrects et n'autorisaient pas le streaming).

Le problème est que le service Web (jax ws) ne reçoit pas le corps de la requête contenant les données.

Il reçoit les données transférées dans les en-têtes.

Nous avons construit un client Java pour le WS - celui-ci fonctionne.

J'ai capturé et comparé le trafic HTTP lors de l'émission des demandes de java et WCF, et la seule différence est dans la façon dont la référence Content-ID est généré lors de la publication des données multipart:

  • WCF utilise http://tempuri/1/... contenu références -id qui donnent de la valeur encodée, comme href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928"

  • client Java utilise "style email" uri, comme href="cid:[email protected]"

Ces rendements dans ce qui suit xop-inclut (Data est le seul élément dans le corps de savon) (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> 

plus tard, dans les données en plusieurs parties, dont le contenu est désigné par 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 

Je suppose qu'il peut un bogue dans le cadre de services Web JAX et il ne reconnaît pas WCF générés + urlencoded Content-ID références uri.

Existe-t-il un moyen de forcer WCF à utiliser des références Content-ID différentes pour le xop: Include?


EDIT: J'ai trouvé le XmlMtomWriter qui a la méthode GenerateUriForMimePart, il est utilisé pour générer Content-ID.

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

Il ne semble pas que la génération d'ID puisse être substituée de quelque manière que ce soit.

Un problème similaire est décrit ici, la réponse fournie ne permet pas: http://social.msdn.microsoft.com/Forums/en/wcf/thread/f90affbd-f431-4602-a81d-cc66c049e351

Répondre

1

Asnwering à moi-même après une longue enquête: pas possible sans réimplémentant l'ensemble XmlMtomWriter et d'autres couches et préoccupations liées à WCF - presque tout ce qui concerne l'implémentation de mtom est interne.

0

Les deux XOP incluent des exemples que vous avez indiqués sont corrects et acceptables selon le W3C. Je me réfère à eux comme le format d'URL et le format Email respectivement.

Je ne suis pas un développeur JAVA, mais je me souviens d'un problème similaire lors de l'interfaçage avec un service Web JAVA particulier. Je me souviens qu'il y avait un bug dans une version particulière de JAVA et après qu'ils (les développeurs JAVA) soient passés à la version suivante, ce problème est tout simplement parti. J'aimerais pouvoir vous fournir plus de détails, mais à ce moment-là, il y avait assez de problèmes pour que je puisse répondre de mon côté du fil et j'étais content d'avoir un article de moins sur le registre des défauts.

//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> 
1

Je sais que c'est une vieille question. Mais je suis confronté au même problème il y a deux jours.

J'ai trouvé un moyen qui fonctionne MAIS c'est un bidon TRÈS TRÈS sale (je le sais, j'ai pensé à ne pas le publier ici mais peut-être que ça aiderait quelqu'un.) J'espère que vous ne m'en voudrez pas.

ContentId est formaté à l'aide de CultureInfo.InvariantCulture. Je n'ai pas trouvé un moyen officiel de le remplacer par un CultureInfo personnalisé. Mais avec l'aide de la réflexion, je l'ai fait fonctionner. L'implémentation suivante est uniquement pour .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); 
    } 
} 

Je n'accepte ma propre "InvariantCulture" qu'après un appel WCF.

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

CultureInfo.InvariantCulture est un objet global de l'Etat. L'activation de ma propre InvariantCulture affecte tous les autres threads. Encore une fois, c'est un hack sale. Mais ça fonctionne.

+0

oui, c'est sale, mais félicitations pour trouver une solution qui fonctionne. Je n'aurais pas pensé à remplacer InvariantCulture par la réflexion, mais il semble que c'est vraiment la seule option. – Marek