2010-02-17 11 views
10

WCF używa http://tempuri/1/number dla identyfikatorów Content-ID podczas obsługi przesyłanych strumieniowo żądań MTOM.WCF: (MTOM) czy istnieje sposób na zmianę schematu używanego w Xop: URL-a odniesień do treści generowanych przez WCF?

Czy jest jakikolwiek sposób wymuszania WCF do użycia różnych odniesień Content-ID dla xop: Include?

Tło problemu:

buduję klienta .NET dla MTOM włączona ws JAX java serwisu WWW, który obsługuje przesyłanie danych strumieniowo duże. Mam ręcznie wykonane usługi i kontakty danych (wygenerowane przez WSDL kontrakty nie były poprawne i nie zezwalano na przesyłanie strumieniowe).

Problem polega na tym, że usługa WWW (jax ws) nie otrzymuje treści żądania zawierającej dane.

Odbiera dane przesyłane w nagłówkach.

Zbudowaliśmy klienta java dla ws - ten działa.

mam zrobione i porównał ruch HTTP przy wydawaniu żądania z Java i WCF, a jedyną różnicą jest to, w jaki sposób odniesienia Content-ID jest generowany podczas wysyłania danych wieloczęściowy:

  • WCF używa http://tempuri/1/... zawartość -id referencje, które dają wartości zakodowanego, jak href="cid:http%3A%2F%2Ftempuri.org%2F1%2F634019957020047928"

  • klienta Java używa "email-styl" URI, jak href="cid:[email protected]"

Te Wydajność następujące xop-zawierającej (danych jest jedynym elementem korpusu mydło) (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> 

później, w danych wielowarstwowym zawartość jest określana przez niezakodowany 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 

Chyba nie może być błąd w ramach jax usług internetowych i nie rozpoznaje WCF generowane + urlencoded Content-ID referencji uRI.

Czy jest jakikolwiek sposób wymuszania WCF do użycia różnych odniesień Content-ID dla xop: Include?


EDIT: Znalazłem XmlMtomWriter który ma metodę GenerateUriForMimePart ta służy do generowania Content-ID.

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

Nie wydaje się, że generowanie identyfikatora jest w jakikolwiek sposób możliwe do zastąpienia.

Podobny problem jest opisany tutaj, odpowiedź pod warunkiem nie pomaga: http://social.msdn.microsoft.com/Forums/en/wcf/thread/f90affbd-f431-4602-a81d-cc66c049e351

Odpowiedz

1

Asnwering do siebie po długim dochodzeniu: Nie jest możliwe bez reimplementing cały XmlMtomWriter i innych powiązanych warstw i obawy w WCF - prawie wszystko zaangażowany w implementacja mtom jest wewnętrzna.

0

Oba XOP zawiera próbki, które wskazałeś są poprawne i akceptowalne zgodnie z W3C. Odnoszę się do nich odpowiednio jako formatu adresu URL i formatu wiadomości e-mail.

Nie jestem programistą JAVA, ale przypomnijmy sobie podobny problem, gdy współpracujemy z konkretną usługą WWW JAVA. Przypominam, że w konkretnym wydaniu JAVA pojawił się błąd, a po tym, jak (programiści JAVA) uaktualnili się do kolejnej wersji, ten problem po prostu zniknął. Żałuję, że nie mogę podać wam więcej szczegółów, ale w tamtym czasie było wystarczająco dużo problemów, abym mógł adresować z mojego końca przewodu i po prostu cieszę się, że mam jeden mniej pozycji w dzienniku wad.

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

Wiem, że to stare pytanie. Ale dwa dni temu stoję przed tym samym problemem.

Znalazłem sposób, który działa, ALE to jest BARDZO BARDZO brudny hack (wiem o tym.) Myślałem o tym, żeby go tutaj nie publikować, ale może to pomogłoby komuś.) Mam nadzieję, że nie będziesz mnie za to winić.

ContentId jest sformatowany przy użyciu CultureInfo.InvariantCulture. Nie znalazłem oficjalnego sposobu na zastąpienie go niestandardową CultureInfo. Ale dzięki refleksji udało mi się go uruchomić. Następująca implementacja dotyczy tylko .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); 
    } 
} 

Włączam moją własną "InvariantCulture" tylko przed wywołaniem WCF.

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

CultureInfo.InvariantCulture jest globalnym obiektem stanu. Włączenie mojej własnej InvariantCulture wpływa na każdy inny wątek. Ponownie, to jest brudny hack. Ale działa.

+0

tak, to jest brudne, ale gratuluję znalezienia rozwiązania, które działa. Nie pomyślałbym o zastąpieniu InvariantCulture przez refleksję, ale wygląda na to, że jest to jedyna opcja. – Marek

Powiązane problemy