[C#/.NET]\f in webservice hoe er uit te krijgen

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
Beste mensen,

Beetje wazige titel, maar ik heb hier hetvolgende probleem:

ik heb een webservice die zijn informatie uit een database haalt. In die database schrijven verschillende apps, en daardoor zou er in somige velden een '\f' karakter (formfeed) in kunnen staan.

Wanneer die webservice nu data ophaal uit die database, en dit doorstuurt naar de bevrager van die webservice gaat dit eigenlijk altijd goed. Tenzij er een \f karakter in staat.

Nu heb ik in de xml specificaties gelezen dat inderdaad de \f geen geldig XML karakter is, en dat het dus logisch is dat dit niet werkt.

Echter, de serialisatie van .net (2.0 gebruik ik, maar 3.5 doet dat ook) haalt die ongeldige karakters (dus mijn \f) er niet uit.
De xml die de webservice dus teruggeeft is foutief.

De applicatie die dan de response van die webservice uitleest klapt vervolgens op het parsen van de xml.



Tot zover de situatieschets.

Nu is het mijn bedoeling om te zorgen dat de webservice de \f (en andere ongeldige tekens) niet meer serialized. Dit is alleen wat lastig.

Als ik 1 objectje retourneer, met daarin twee stringentjes had ik het wel voor die twee stringetjes een search/replace gedaan.
Echter gaat het om een hele berg requests, waarin ook aardig wat complexe datatypen (gewoon custom classes) terug gestuurd worden.

Nu vroeg ik me af of ik op de een of andere manier tussen het serializatieproces van .net kan komen. Of dat ik kan zeggen dat ik zelf wil serializen ipv dat ik dat door .net laat doen.

Heeft iemand hier ervaring mee? of zijn er andere oplossingen / ideeen over mijn probleem?

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • Nick_S
  • Registratie: Juni 2003
  • Laatst online: 17-09 12:49

Nick_S

++?????++ Out of Cheese Error

Volgens een mailinglijst die ik vond is het voldoende om XML 1.1 te gaan versturen ipv. XML 1.0. Mischien is dat een optie?
You can use character entities for control codes in XML 1.1. The
simplest way for them to fix their bug may be for them to change the XML
declaration in their documents to specify XML 1.1 rather than XML 1.0.

'Nae King! Nae quin! Nae Laird! Nae master! We willna' be fooled agin!'


Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
dat zou wel heel makkelijk zijn. :)
(en je weet het, als ze zeggen dat het te mooi is om waar te zijn.... ;) )

ik ga het morgen direct proberen tnx

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
BasieP schreef op dinsdag 04 augustus 2009 @ 22:08:
dat zou wel heel makkelijk zijn. :)
(en je weet het, als ze zeggen dat het te mooi is om waar te zijn.... ;) )

ik ga het morgen direct proberen tnx
mmm
Of het is zo'n enorm simpele setting dat er op internet niks over te vinden is, of je kan in .net 2.0 niet je webservice xml 1.1 laten gebruiken... :(

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • Nick_S
  • Registratie: Juni 2003
  • Laatst online: 17-09 12:49

Nick_S

++?????++ Out of Cheese Error

BasieP schreef op woensdag 05 augustus 2009 @ 08:38:
[...]

mmm
Of het is zo'n enorm simpele setting dat er op internet niks over te vinden is, of je kan in .net 2.0 niet je webservice xml 1.1 laten gebruiken... :(
Ik kan je helaas ook niet verder helpen. Ik ben Java programmeur...

'Nae King! Nae quin! Nae Laird! Nae master! We willna' be fooled agin!'


Acties:
  • 0 Henk 'm!

  • Coca-Cola
  • Registratie: Maart 2001
  • Laatst online: 07:01
Ik heb ooit snel wat code in elkaar gedraaid die checked of een string invalid xml characters bevat omdat aangeleverde data het soms ook niet zo nauw nam. Voor mij was het voldoende om deze characters te verwijderen, maar vervangen door iets anders is net zo makelijk.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private String RemoveInvalidXml(String input)
{
    StringBuilder output = new StringBuilder(); // Used to hold the output.

    Char current; // Used to reference the current character.

    if (input == null)
    {
        return String.Empty;
    } // vacancy test.

    for (int i = 0; i < input.Length; i++)
    {
        current = input[i];
        if ((current == 0x9) || (current == 0xA) || (current == 0xD) ||
            ((current >= 0x20) && (current <= 0xD7FF)) ||
            ((current >= 0xE000) && (current <= 0xFFFD)) ||
            ((current >= 0x10000) && (current <= 0x10FFFF)))
        {
            output.Append(current);
        }
    }
    return output.ToString();
}


Ik zie nu dat dit nog wel een warning geeft, dus due Char Current kan misschien nog wat netter

Acties:
  • 0 Henk 'm!

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Een mogelijke oplossing zou zijn

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FooClass
{
  private string bar;
  
  [XmlIgnore]
  public string Bar
  {
    get { return bar; }
    set { _bar = value; }
  }

  [XmlAttribute("Bar")]
  public string Bar_xml
  {
    get { return bar.replace('\f', ''); }
  }
}


Maar dat is misschien toch een beetje een hack.

Je kunt natuurlijk ook gewoon geforceerd illegale karakters al uit een string strippen wanneer je de data uit je database query in je custom data access of data transfer classes gooit. Ik weet alleen niet of dat past binnen de applicatie als geheel. Zijn er andere, niet aan een xml webservice gerelateerde clients, die wèl per sé die form feed en andere control characters behouden willen hebben?

Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

R4gnax schreef op woensdag 05 augustus 2009 @ 11:19:
Een mogelijke oplossing zou zijn

Maar dat is misschien toch een beetje een hack.
Tip: Je kan bar_xml ook private maken. Scheelt weer een extra attribuut in je Intellisense, en de class user heeft het toch niet nodig.

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
het strippen van de chars uit een string is niet het probleem. Echter gaat het om een grote applicatie, met daarin veel objecten die op hun beurt weer veel strings (kunnen) bevatten.

Het langslopen van alle strings is opzich al een hells karwij, maar omdat ik objecten retourneer is het al een stuk lastiger om van alle attributen van die objecten de illigale chars te vervangen.

Ik wil het dus op een ander niveau doen.

trouwens heb ik zojuist WCF getest met een wsHttp endpoint en met een wsHttp2007 endpoint, en die lijken het allebij te doen.
Dat zou natuurlijk wel een reden zijn WCF te gaan gebruiken

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Mijn gok is dat je een SoapExtension moet schrijven om nadat het bericht gebouwd is wat post-processing te doen op de rauwe XML. Dat lijkt me eigenlijk het makkelijkst, als het om zoveel classes gaat dat et geen doen is om die dingen aan te passen.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
Grijze Vos schreef op woensdag 05 augustus 2009 @ 12:38:
Mijn gok is dat je een SoapExtension moet schrijven om nadat het bericht gebouwd is wat post-processing te doen op de rauwe XML. Dat lijkt me eigenlijk het makkelijkst, als het om zoveel classes gaat dat et geen doen is om die dingen aan te passen.
tnx,

werkt als een tierelier. :)
Ik heb nu inderdaad een generieke oplossing voor al mijn code. Op mijn interfaces (webmethods) moet ik even een extra attribute zetten, maar dan gaat het verder ook prima.

Hier is mijn code

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Web.Services.Protocols;

namespace xxxxxx
{
    public class FilterInvalidCharsSoapExtension : SoapExtension
    {
        Stream soapStream;
        Stream tempStream;

        public override Stream ChainStream(Stream stream)
        {
            soapStream = stream;
            tempStream = new MemoryStream();
            return tempStream;
        }

        public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
        {
            return null;
        }

        public override object GetInitializer(Type WebServiceType)
        {
            return null;
        }

        public override void Initialize(object initializer)
        {
        }

        public override void ProcessMessage(SoapMessage message)
        {
            switch (message.Stage)
            {
                case SoapMessageStage.BeforeSerialize:
                    break;
                case SoapMessageStage.AfterSerialize:
                    FilterResponseInvalidChars();
                    break;
                case SoapMessageStage.BeforeDeserialize:
                    FilterRequestInvalidChars();
                    break;
                case SoapMessageStage.AfterDeserialize:
                    break;
            }
        }

        private void filter(Stream from, Stream to)
        {
            TextReader reader = new StreamReader(from);
            TextWriter writer = new StreamWriter(to);

            string s = reader.ReadToEnd();

            //valid XML chars:
            //#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

            List<char> invalidChars = new List<char>();
            invalidChars.Add(Convert.ToChar(0x0));  //\0=end string
            invalidChars.Add(Convert.ToChar(0x1));
            invalidChars.Add(Convert.ToChar(0x2));
            invalidChars.Add(Convert.ToChar(0x3));
            invalidChars.Add(Convert.ToChar(0x4));
            invalidChars.Add(Convert.ToChar(0x5));
            invalidChars.Add(Convert.ToChar(0x6));
            invalidChars.Add(Convert.ToChar(0x7));  //\a=beep
            invalidChars.Add(Convert.ToChar(0x8));  //\b=backspace
            invalidChars.Add(Convert.ToChar(0xB));
            invalidChars.Add(Convert.ToChar(0xC));  //\f=formfeed

            for (int i = 0xE; i <= 0x1F; i++)
                invalidChars.Add(Convert.ToChar(i));

            for (int i = 0xD800; i <= 0xDFFF; i++)
                invalidChars.Add(Convert.ToChar(i));

            invalidChars.Add(Convert.ToChar(0xFFFE));
            invalidChars.Add(Convert.ToChar(0xFFFF));

            foreach (char c in invalidChars)
                s = s.Replace(c.ToString(), "");

            //xml representation of the chars (die volgens mij wel valide zouden moeten zijn, maar waar stomme deserializatie nog steeds over valt)
            s = s.Replace("&#x7;", "");
            s = s.Replace("&#x8;", "");
            s = s.Replace("&#xB;", "");
            s = s.Replace("&#xC;", "");

            writer.WriteLine(s);
            writer.Flush();
        }

        public void FilterRequestInvalidChars()
        {
            filter(soapStream, tempStream);
            tempStream.Position = 0;
        }

        public void FilterResponseInvalidChars()
        {
            tempStream.Position = 0;
            filter(tempStream, soapStream);
        }
    }

    // Create a SoapExtensionAttribute for the SOAP Extension that can be applied to an XML Web service method.
    [AttributeUsage(AttributeTargets.Method)]
    public class FilterInvalidCharsSoapExtensionAttribute : SoapExtensionAttribute
    {
        public override Type ExtensionType
        {
            get { return typeof(FilterInvalidCharsSoapExtension); }
        }

        public override int Priority { get; set; }
    }
}

This message was sent on 100% recyclable electrons.


Acties:
  • 0 Henk 'm!

  • Coca-Cola
  • Registratie: Maart 2001
  • Laatst online: 07:01
Is die methode niet redelijk inefficient? Ik weet niet precies hoe string.replace werkt, maar het lijkt me dat er toch door de hele string heen gelopen moet worden en nu moet je dat n keer doen (n = #invalid chars). In die methode die ik gaf check je elke char 1 keer. Bovendien vul je nu voor elke request die hele invalid char list, terwijl je dat ook 1 keer kan doen.

Zal trouwens wel niet heel veel schelen, maar ik heb geen idee hoe performant die webservice moet zijn ;)

Acties:
  • 0 Henk 'm!

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
Coca-Cola schreef op maandag 10 augustus 2009 @ 17:39:
Is die methode niet redelijk inefficient? Ik weet niet precies hoe string.replace werkt, maar het lijkt me dat er toch door de hele string heen gelopen moet worden en nu moet je dat n keer doen (n = #invalid chars). In die methode die ik gaf check je elke char 1 keer. Bovendien vul je nu voor elke request die hele invalid char list, terwijl je dat ook 1 keer kan doen.

Zal trouwens wel niet heel veel schelen, maar ik heb geen idee hoe performant die webservice moet zijn ;)
punt is dat de tekst (de string s; het soaprequest/response) korter is dan de lijst met invalid chars.

momenteel fiets je 1x door die lange lijst met invalid chars heen, en meerdere malen door die korte 'lijst' (string) met tekst.

On the other hand hoef je natuurlijk geen lijst met invalid chars op te bouwen wanneer je de chars op nummer vergelijkt...
(ff testcase bouwen :P)

Edit:
omfg..
een verschil van 22 seconden...
mijn oude methode deed er 23 seconden over om 1000x uit te voeren.... :P


offtopic:
Trouwens mis ik de PHP replace functie wel, want daar kan je arrays instoppen als parameter ;)

[ Voor 13% gewijzigd door BasieP op 21-09-2009 17:34 ]

This message was sent on 100% recyclable electrons.

Pagina: 1