Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C# 2.0] XML serializable class mag niet internal

Pagina: 1
Acties:

  • DrDelete
  • Registratie: Oktober 2000
  • Laatst online: 30-11 21:50
Ik heb voor een webservice een class nodig die serializable is. .NET haalt deze bij gebruik van de webservice door de XML serializer.

Een van de eisen is dat deze class public moet zijn anders werkt de XML deserialization niet. Door deze eis wordt mijn public API van mijn class library vervuild met een class die eigenlijk alleen voor intern gebruik is.

Hoe kan ik er voor zorgen dat deze class toch XML serializable is maar niet in de public API van mijn classlib zichtbaar wordt....?

  • whoami
  • Registratie: December 2000
  • Laatst online: 15:44
Ik vind het niet logisch dat deze class niet in de public API van je library zit ....

Ik bedoel; aangezien de webservice deze class gebruikt, is het logisch dat deze ook public moet zijn. De client die je webservice gebruikt, moet nl. 'kennis' hebben van deze class; waarom wil je ze dan internal / private / whatever ?

In situaties waar ik niet wil dat de 'client' niet met een bepaalde class rechtstreeks in aanraking kom, maar ik deze class niet internal kan maken, dan plaats ik die class in een andere namespace.
De client moet dan al weten dat hij die class daar kan vinden; als hij ze gebruikt, dan zal het niet 'toevallig' zijn.
Het is natuurlijk geen middel om te verhinderen dat deze class gebruikt wordt.

[ Voor 38% gewijzigd door whoami op 22-10-2007 12:50 ]

https://fgheysels.github.io/


  • barfieldmv
  • Registratie: Maart 2004
  • Laatst online: 10-10 12:36
DrDelete schreef op maandag 22 oktober 2007 @ 12:46:
Ik heb voor een webservice een class nodig die serializable is. .NET haalt deze bij gebruik van de webservice door de XML serializer.

Een van de eisen is dat deze class public moet zijn anders werkt de XML deserialization niet. Door deze eis wordt mijn public API van mijn class library vervuild met een class die eigenlijk alleen voor intern gebruik is.

Hoe kan ik er voor zorgen dat deze class toch XML serializable is maar niet in de public API van mijn classlib zichtbaar wordt....?
Keuzes:
Gebruik in plaats van een public API een public Interface
Stop de Class in een aparte assembly

  • DrDelete
  • Registratie: Oktober 2000
  • Laatst online: 30-11 21:50
whoami schreef op maandag 22 oktober 2007 @ 12:49:
Ik vind het niet logisch dat deze class niet in de public API van je library zit ....

Ik bedoel; aangezien de webservice deze class gebruikt, is het logisch dat deze ook public moet zijn. De client die je webservice gebruikt, moet nl. 'kennis' hebben van deze class; waarom wil je ze dan internal / private / whatever ?

In situaties waar ik niet wil dat de 'client' niet met een bepaalde class rechtstreeks in aanraking kom, maar ik deze class niet internal kan maken, dan plaats ik die class in een andere namespace.
De client moet dan al weten dat hij die class daar kan vinden; als hij ze gebruikt, dan zal het niet 'toevallig' zijn.
Het is natuurlijk geen middel om te verhinderen dat deze class gebruikt wordt.
oeps.. was even vergeten bij te vermelden dat de "client" de webservice helemaal niet ziet (of weet van heeft). Ik heb de webservice gewrapped in een client-vriendelijke class. Deze client-vriendelijke class is public, de webservices zijn internal.

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Bij serialisatie, of eigenlijk deserialisatie maakt het .net framework voor jouw de class opnieuw aan en zet daarna de properties van die class. Als jouw class internal is, kan .net nooit een nieuw instantie van jouw class creeren.

Een mogelijke oplossing is het gebruik van ISerializable. Je kunt de class public maken, maar de constructors private/protected. Alleen de constructor voor ISerializable hoeft public te zijn.

Overigens snap ik niet waarom je class internal is. Als je al een wrapper voor de webservice heeft, dan kan de client toch al helemaal niet bij de 'business' classes komen.. internal is gezien de informatie welke je hier hebt gegeven volledig overbodig. Sterker nog in plaats van dat het de eind gebruiker beperkt, beperkt het nu jouw. Het gebruik van private (ipv protected) vind ik al discutabel. Als een van mijn developers private gebruikt terwel de class niet sealed is of de private variable bescherm wordt door een public/protected property, dan heeft hij/zij al veel uit te leggen. Je moet bij mij echt met heel erg goede argumenten komen wil ik een internal class accepteren.

If it isn't broken, fix it until it is..


  • whoami
  • Registratie: December 2000
  • Laatst online: 15:44
ISerializable werkt afaik niet met Xml Serialization; je hebt IXmlSerializable nodig.
En voor XML serialization moet je class zowiezo public zijn.

En de speciale constructor voor ISerializable hoeft ook niet public te zijn
oeps.. was even vergeten bij te vermelden dat de "client" de webservice helemaal niet ziet (of weet van heeft). Ik heb de webservice gewrapped in een client-vriendelijke class. Deze client-vriendelijke class is public, de webservices zijn internal
Dus, je client heeft een reference naar die client-vriendelijke class ? En die client-vriendelijke class heeft de webservices gewrapped ?
Dat wil dus zeggen dat de webservices ook bij de client staan, en de client dus meer heeft dan enkel een web-reference (proxy) naar die webservice ? :?

Je client hoeft toch enkel een proxy te hebben naar die webservice ? Als je je business classes en alle andere zut die 'intern' door de WS gebruikt wordt, niet aan de client wil geven, dan kan je die t och gewoon -zoals reeds gezegd- in een andere assembly plaatsen ?
De server waar je WS staat, heeft dan een referentie naar die assembly, en je client heeft een webreference naar je webservice. Op die manier kan je client niet aan de classes die jij wilt 'hiden'.

https://fgheysels.github.io/


  • DrDelete
  • Registratie: Oktober 2000
  • Laatst online: 30-11 21:50
whoami schreef op maandag 22 oktober 2007 @ 14:21:
ISerializable werkt afaik niet met Xml Serialization; je hebt IXmlSerializable nodig.
En voor XML serialization moet je class zowiezo public zijn.

En de speciale constructor voor ISerializable hoeft ook niet public te zijn


[...]

Dus, je client heeft een reference naar die client-vriendelijke class ? En die client-vriendelijke class heeft de webservices gewrapped ?
Dat wil dus zeggen dat de webservices ook bij de client staan, en de client dus meer heeft dan enkel een web-reference (proxy) naar die webservice ? :?

Je client hoeft toch enkel een proxy te hebben naar die webservice ? Als je je business classes en alle andere zut die 'intern' door de WS gebruikt wordt, niet aan de client wil geven, dan kan je die t och gewoon -zoals reeds gezegd- in een andere assembly plaatsen ?
De server waar je WS staat, heeft dan een referentie naar die assembly, en je client heeft een webreference naar je webservice. Op die manier kan je client niet aan de classes die jij wilt 'hiden'.
was het maar zo makkelijk...

De webservices zijn inderdaad op de client geinstalleerd. De client proxy call't de webservice eerst lokaal. De webservice die lokaal staat haalt uit een database de informatie op over de endpoint URL. Deze constructie is niet door mij bedacht maar is een archictectuurgedachte van een stukje middelware die deze webservice aanbiedt (Hermes Messaging Gateway 2.0, gehost in TomCat)


De WSDL's die meegegeven zijn bij de webservice zijn niet WS-I basic profile 1.1 compliant waardoor de client proxy niet gegenereerd kon worden. Daar boven op moest ik een eigen Soap With Attachments soapextension schrijven. De client proxy moest ik handmatig maken met wat low level truukjes om data naar de soapextension te krijgen.

Uiteindelijk wil ik de client proxy niet naar de buitenwereld brengen vanwege de complexiteit. Het doel van een public API binnen een class library is om de client (lees: developer) het makkelijk te maken om de main scenario's van je use cases af te dekken. Met mijn class library ben ik daar heel ver mee gekomen en het ziet er op het oog zeer duidelijk en simpel uit (aan de buitenkant).

[ Voor 9% gewijzigd door DrDelete op 22-10-2007 15:24 ]


  • DrDelete
  • Registratie: Oktober 2000
  • Laatst online: 30-11 21:50
Ik ben er uit!

Door gebruik te maken van de IXmlSerializable interface kan ik zelf bepalen wat ik de XML serializer laat serializeren. Ik kan dan de class die in de root van de class library namespace zit ook daardoor hergebruiken voor het serializeren (ik had eerst een extra class gemaakt die alleen voor het serializeren gebruikt werd, maar heb het nu gecombineerd)

code:
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
[Serializable]
    public class Payload : IXmlSerializable
    {
        private byte[] data;
        
        /// <summary>
        /// Default contructor is hidden, use the constructor initializers instead.
        /// </summary>
        private Payload()
        {
        }

        /// <summary>
        /// Use this constructor to load the payload by file.
        /// </summary>
        /// <param name="filename"></param>
        public Payload(string filename)
        {
            if (!File.Exists(filename))
            {
                throw new ArgumentException(
                    ExceptionResourceManager.GetMessage(
                        ExceptionResourceIdentifiers.PayloadFilenameNotFound, 
                            filename), 
                    "filename");
            }

            using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                int length = (int)stream.Length;

                this.data = new byte[length];
                
                stream.Read(this.data, 0, length);
            }
        }

        /// <summary>
        /// Use this constructor to load the payload by a byte array.
        /// </summary>
        /// <param name="data"></param>
        public Payload(byte[] data)
        {
            this.data = data;
        }

        /// <summary>
        /// Payload in array of bytes.
        /// </summary>
        public byte[] GetData()
        {
            return this.data;
        }

        #region IXmlSerializable Members

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");

            this.data = Encoding.Default.GetBytes(reader.ReadString());
        }

        public void WriteXml(XmlWriter writer)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");

            writer.WriteString(Encoding.Default.GetString(this.data));
        }

        #endregion
    }
Pagina: 1