20

W moim web method, otrzymuję obiekt klasy C# strony trzeciej. Klasa encji to nic innego jak DataContract. Ta klasa encji jest dość złożona i ma właściwości różnych typów, niektóre właściwości są również kolekcjami. Oczywiście te powiązane typy to także Kontakty danych.Linq do Xml VS XmlSerializer VS DataContractSerializer

Chcę serializować tę encję DataContract na XML jako część logiki biznesowej mojej usługi internetowej. Nie mogę użyć bezpośrednio kodu DataContractSerializer (na obiekcie, który otrzymuję w metodzie internetowej), ponieważ schemat XML jest zupełnie inny. W związku z tym XML generowany przez DataContractSerializer nie zostanie zweryfikowany względem schematu.

Nie jestem w stanie zakończyć podejścia, które powinienem zastosować w celu wdrożenia. Mogę myśleć o następujących metod wdrażania:

  1. LINQ to XML - To wygląda ok, ale trzeba utworzyć drzewo XML (to znaczy elementy lub reprezentacji XML instancji klasy) ręcznie dla każdego rodzaju obiektu. Ponieważ istnieje wiele klas jednostek i są ze sobą powiązane, myślę, że to zbyt dużo pracy, aby ręcznie pisać elementy XML. Poza tym będę musiał dalej modyfikować drzewo XML, kiedy klasa encji wprowadzi jakąś nową właściwość. Nie tylko to, kod generowania drzewa XML wyglądałby trochę niezgrabnie (przynajmniej w wyglądzie) i byłby trudniejszy do utrzymania/zmiany przez jakiegoś innego programistę w przyszłości; on/ona będzie musiał przyjrzeć się tak dokładnie, aby zrozumieć, jak generowany jest ten XML.

  2. XmlSerializer - Mogę pisać własne podmiot klas, które reprezentują strukturę XML chcę. Teraz muszę skopiować szczegóły z przychodzącego obiektu do obiektu moich własnych klas. To jest dodatkowa praca (dla .NET również po wykonaniu kodu!). Następnie mogę użyć XmlSerializer na moim obiekcie do wygenerowania XML. W takim przypadku będę musiał utworzyć klasy jednostek, a gdy jednostka zewnętrzna zostanie zmodyfikowana, będę musiał dodać nową właściwość w mojej klasie. (z atrybutami XmlElement lub XmlAttibute). Ale ludzie polecają DataContractSerializer nad tym, więc nie chcę tego finalizować, chyba że wszystkie aspekty są dla mnie jasne.

  3. DataContractSerializer - Znowu tutaj, będę musiał napisać własną klasę encji ponieważ mam żadnej kontroli nad DataContracts osób trzecich. I muszę skopiować szczegóły z przychodzącego obiektu do obiektu moich własnych klas. To jest dodatkowa praca. Jednak ponieważ DataContractSerializer nie obsługuje atrybutów Xml, będę musiał zaimplementować IXmlSerializable i wygenerować wymagany Xml w metodzie WriteXml. DataContractSerializer jest szybszy niż XmlSerializer, ale znowu będę musiał obsłużyć zmiany (w WriteXml), jeśli zmieni się podmiot zewnętrzny.

Pytania:

  • które podejście jest najlepsze w tym scenariuszu, biorąc pod uwagę wydajność też?
  • Czy możesz zaproponować lepsze podejście?
  • Czy warta rozważenia jest DataContractSerializer (ponieważ ma lepszą wydajność niż XmlSerilaizer), gdy klasa przychodzącego obiektu może ulec zmianie?
  • Czy LINQ powinien być naprawdę używany do serializacji? Czy jest to naprawdę dobre dla rzeczy innych niż zapytanie?
  • Czy XmlSerializer może być preferowany zamiast LINQ w takich przypadkach? Jeśli tak, dlaczego?

Odpowiedz

9

Zgadzam się z odpowiedzią @Werner Strydom.

Zdecydowałem się użyć XmlSerializer, ponieważ kod staje się łatwy w utrzymaniu i oferuje oczekiwaną wydajność. Najważniejsze jest to, że daje mi pełną kontrolę nad strukturą XML.

To jak ja rozwiązać mój problem:

I utworzony podmiot klas (reprezentujących różne typy elementów XML) jak na moje wymagania, a przekazywane instancję klasy głównej (klasa reprezentująca element główny) przez XmlSerializer .

Małe wykorzystanie LINQ w przypadku 1: związek M:

Gdziekolwiek chciałem sam element (słownie Employee) wiele razy pod konkretnego węzła (słownie Department), oświadczyłem właściwość typu List<T>. na przykład public List<Employee> Employees w klasie Department. W takich przypadkach XmlSerializer oczywiście dodał element o nazwie Employees (który jest grupą wszystkich elementów Employee) pod węzłem Department. W takich przypadkach użyłem LINQ (po tym, jak XmlSerializer serializował obiekt .NET) w celu manipulowania XElement (tj. XML) generowanym przez XmlSerializer. Używając LINQ, po prostu wstawiłem wszystkie węzły Employee bezpośrednio pod węzeł Department i usunąłem węzeł .

Jednak uzyskałem oczekiwaną wydajność przez połączenie xmlSerializer i LINQ.

Wadą jest to, że wszystkie utworzone przeze mnie klasy musiały być publiczne, gdy mogły być równie dobrze wewnętrzne!

Dlaczego nie DataContractSerializer i LINQ-to-XML?

  • DataContractSerializer nie pozwala używać atrybutów XML (chyba że wdrożenie IXmlSerializable). Zobacz types supported by DataContractSerializer.
  • (i IXmlSerializable) sprawia, że ​​kod jest niezgrabny podczas tworzenia złożonej struktury XML, a ten kod na pewno spowodowałby, że inni programiści zarysowaliby swoje głowy, jednocześnie zachowując/zmieniając.

Czy istnieje inny sposób?

  • Tak. Jak wspomniano w @Werner Strydom, możesz bardzo dobrze generować klasy przy użyciu XSD.exe lub narzędzia takiego jak Xsd2Code i pracować bezpośrednio z nimi, jeśli jesteś zadowolony z powstałych klas.
7

Wybieram XmlSerializer, ponieważ jest najbardziej konserwowalny dla niestandardowego schematu (zakładając, że masz XSD). Po zakończeniu projektowania systemu sprawdź jego wydajność i określ, czy serializacja XML powoduje problemy. Jeśli tak, możesz go zastąpić czymś, co wymaga więcej pracy i przetestować ponownie, aby sprawdzić, czy są jakieś zyski. Ale jeśli serializacja XML nie jest problemem, to masz możliwy do utrzymania kod.

Czas potrzebny do przeanalizowania małego fragmentu danych XML może być nieistotny w porównaniu do komunikacji z bazą danych lub systemami zewnętrznymi. W systemach z dużą pamięcią (16 GB +) możesz stwierdzić, że GC jest wąskim gardłem w .NET 4 i wcześniejszych (.NET 4.5 próbuje rozwiązać ten problem), szczególnie gdy pracujesz z bardzo dużymi zbiorami danych i strumieniami.

Użyj AutoMapper, aby odwzorować obiekty utworzone przez XSD.EXE na twoje obiekty. Umożliwi to zmianę projektu bazy danych bez wpływu na serwis internetowy.

Jedna rzecz, która jest wspaniała w LINQ to XML to XSD validation. Ma to jednak wpływ na wydajność.

1

Inną opcją jest wykorzystanie LINQ i Reflection do stworzenia ogólnej klasy do serializacji obiektu do XML. Dobry przykład można znaleźć pod adresem http://primecoder.blogspot.com/2010/09/how-to-serialize-objects-to-xml-using.html. Nie jestem pewien, jak powinien wyglądać twój XML pod koniec dnia, ale jeśli jest dość prosty, może to załatwić sprawę. Nie trzeba wprowadzać zmian, ponieważ klasy encji dodają/usuwają/zmieniają właściwości, i można tego użyć we wszystkich obiektach (i innych projektach, jeśli są przechowywane w bibliotece narzędziowej DLL).

+0

Dzięki za udostępnienie linku. Dostarczone tam rozwiązanie nie jest przydatne dla mojego problemu, ale pomogło poznać jeszcze jeden sposób korzystania z LINQ! – Learner