I am implementing the Builder Pattern in order to generate a set of objects. These objects then have to be serialized to XML and deserialized from XML.
I know how to perform the serialization and deserialization however I am unsure how to integrate it into the design pattern.
For example suppose my code uses the builder to create products foo and bar. My first thought is to put a serialize function on each one because each product knows what to serialize.
My next thought was to put the deserialization in the Director or the ConcreteBuilder.
What I don't like about this is that the serialization and deserialization functions will be in different places - one in the file for the declaration of the foo and bar objects and the other in the files for something else. I am worried that they might end up becoming out of sync with each other as I work on the product classes.
My final thought was for the Director or ConcreteBuilder to perform the serialization and deserialization. What I don't like about that is the products then have to know which builder was used or know who the Director is.
To clarify - there are two situations where a product can be created:
User clicks on a button in the user interface
User loads a XML project
Can you not simply have a static serialize/deserialize class and create a generic method that can take any type of object? Isn't the pattern simply for building the objects? You can then serialize as you wish?
Something like:
public static string Serialize<T>(T data)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
StringWriter sw = new StringWriter();
xmlSerializer.Serialize(sw, data);
return sw.ToString();
}
My current solution is to have the Product perform the serialization and the ConcreteBuilder perform the deserialization, then put both the Product and it's ConcreteBuilder declarations into the same source file.
Although the task is spread across two classes it is at least kept together in one file.
Any better solutions are appreciated.
Related
In my .net code I am consuming a third-party asmx service that provides me data in Xml format. So basically, I am recieving a structure in a form of XmlNode:
<PostcodeEntry>
<Postcode>13542</Postcode>
<Postcodename>Odessa</Postcodename>
</PostcodeEntry>
Currently, to map it to my POCO object I have to manually iterate through a corresponding ChildNode's and retrieve their InnerText value to get the actual data:
var PostCodeNode = entryNode.SelectSingleNode("Postcode");
if (PostCodeNode != null)
{
result.PostCode = PostCodeNode.InnerText;
}
In case I need to map a large info structure, the code grows to a messy code-scroll.
Is there a way I can improve this so I don't have to write the parsing manually? What is the best practice for this?
I believe that you have different options depending on how you get your data and how you like to design your code etc. From your brief description I can think of at least these two:
Create an XML Serializer - for example by marking up your class with Xml Attributes and de-serialize the XML directly as your desired object via the serializer. The disadvantage of this approach is that you will create a strong coupling between your serializer and your business object. Please take a look at something like this: http://www.switchonthecode.com/tutorials/csharp-tutorial-xml-serialization.
Create a proxy object and map your proxy object to your business object. You can create the proxy object either by using a WSDL exposed by the asmx service, or by using the XSD.exe tool or similar (you may need to first generate an XSD based on the XML if the XML is not already described by an XSD). Then you can map the properties of your proxy object to the properties of your business object. This will provide you a more clean separation between the objects, but at the same time it requires more work.
Br. Morten
You can create SoapClient object for WebService, then you can return the Response as List<>. You need to change the Ouput response to List<>.
example Consilder this the webservice to consume, http://xxx.xx.xxx.xxx/CosmosService/Cm_Service.asmx
then add Service Reference in your application, Click On Advanced Button, change the Collection Type System.Collections.GenericList.
then you can Consume WebService Methods as List<> directly like this
CosmosRef.CM_ServiceSoapClient client = new CosmosRef.CM_ServiceSoapClient();
List<CosmosRef.Product> listProduct = client.GetAllProducts("Computers", 1);
dataGrid1.DataContext = listProduct;
Let's say we have a business object, let's call it a Foo, which contains an ordered list of Bars. We pass this Foo around as XML.
We have a class which deserializes a Foo XML node (FooXMLDeserializer) which itself uses a class which deserializes the child Bar XML nodes (BarXMLDeserializer).
Now, I'm adding some functionality to the BarXMLDeserializer that maintains some state such that if FooXMLDeserializer is called on two separate Foo nodes without reseting the BarXMLDeserializer's state, the results may be invalid. BarXMLDeserializer does not know when it has processed the final Bar in a Foo.
Is there some way that I can design the BarXMLDeserializer class to communicate to developers working on consuming classes that it has state and must be reset for each Foo?
Further info:
My change solves a minor enough problem in our code that I won't be able to convince my manager to let me spend X days redesigning the whole system to nicely handle this case.
If it matters, BarXMLDeserializer keeps is state in a BarStateTracker class which is internal to it.
Programming in C#, but looking for a more general solution.
Thanks.
Expose your serializer only as a static method:
// no public constructor, etc
var deserializer = BarXMLDeserializer.CreateNew();
Then, when you have finished deserializing data, mark a field in your object. If the field is set, throw an exception if the same instance is used to deserialize more data when the deserialize method is called.
if(IsInstanceExhausted)
throw new InvalidOperationException("You must use a fresh instance.");
They'll figure it out after their first exception. In addition, mark your class as IDisposable so that code naturally uses using statements:
using(var deserializer = BarXMLDeserializer.CreateNew())
{
}
The list goes on of additional ways. ALTERNATIVELY, you could simply design your Deserializer to clear it's state or reset after a deserialization attempt, or to clear the state at the beginning of a deserialization attempt.
I'm developing a system to pick up XML attachments from emails, via Exchange Web Services, and enter them into a DB, via a custom DAL object that I've created.
I've manage to extract the XML attachment and have it ready as a stream... they question is how to parse this stream and populate a DAL object.
I can create an XMLTextReader and iterate through each element. I don't see any problems with this other than that I suspect there is a much slicker way. The reader seems to treat the opening tag, the content of the tag and the closing tag as different elements (using reader.NodeType). I expected myValue to be considered one element rather than three. Like I said, I can get round this problem, but I'm sure there must be a better way.
I came across the idea of using an XML Serializer (completely new to me) but a quick look suggested that these can't handle ArrayLists and List (I'm using List).
Again, I'm new to LINQ, but LINQ-to-XML has also been mentioned, but examples I've seen seem rather complex - though that my simply be my lack of familiarity.
Basically, I don't want a cludged system, but I don't want to use any complicated technique with a learning curve, just because it's 'cool'.
What is the simplest and most effective way of translating this XML/Stream in to my DAL objects?
XML Sample:
<?xml version="1.0" encoding="UTF-8"?>
<enquiry>
<enquiryno>100001</enquiryno>
<companyname>myco</companyname>
<typeofbusiness>dunno</typeofbusiness>
<companyregno>ABC123</companyregno>
<postcode>12345</postcode>
<contactemail>me#example.com</contactemail>
<firstname>My</firstname>
<lastname>Name</lastname>
<vehicles>
<vehicle>
<vehiclereg>54321</vehiclereg>
<vehicletype>Car</vehicletype>
<vehiclemake>Ford</vehiclemake>
<cabtype>n/a</cabtype>
<powerbhp>130</powerbhp>
<registrationdate>01/01/2003</registrationdate>
</vehicle>
</vehicles>
</enquiry>
Update 1:
I'm trying to deserialize, based on Graham's example. I think I've set up the DAL for serialization, including specifying [XmlElement("whatever")] for each property. And I've tried to deserialize using the following:
SalesEnquiry enquiry = null;
XmlSerializer serializer = new XmlSerializer(typeof(SalesEnquiry));
enquiry = (SalesEnquiry)serializer.Deserialize(stream);
However, I get an exception:'There is an error in XML document (2, 2)'. The innerexception states {"<enquiry xmlns=''> was not expected."}
Conclusion (updated):
My previous problem was the fact that the element in the XML file (Enquiry) != the name of the class (SalesEnquiry). Rather than an [XmlElement] attribute for the class, we need an [XmlRoot] attribute instead. For completeness, if you want a property in your class to be ignored during serialization, you use the [XmlIgnore] attribute.
I've successfully serialized my object, and have now successfully taken the incoming XML and de-serialized it into a SalesEnquiry object.
This approach is far easier than manually parsing the XML. OK, there has been a steep learning curve, but it was worth it.
Thanks!
If your XML uses a schema (i.e. you're always going to know what elements appear, and where they appear in the tree), you could use XmlSerializer to create your objects. You'd just need some attributes on your classes to tell the serializer what XML elements or attributes they correspond to. Then you just load up your XML, create a new XmlSerializer with the type of the .NET object you want to create, and call the Deserialize method.
For example, you have a class like this:
[Serializable]
public class Person
{
[XmlElement("PersonName")]
public string Name { get; set; }
[XmlElement("PersonAge")]
public int Age { get; set; }
[XmlArrayItem("Child")]
public List<string> Children { get; set; }
}
And input XML like this (saved in a file for this example):
<?xml version="1.0"?>
<Person>
<PersonName>Bob</PersonName>
<PersonAge>35</PersonAge>
<Children>
<Child>Chris</Child>
<Child>Alice</Child>
</Children>
</Person>
Then you create a Person instance like this:
Person person = null;
XmlSerializer serializer = new XmlSerializer(typeof(Person));
using (FileStream fs = new FileStream(GetFileName(), FileMode.Open))
{
person = (Person)serializer.Deserialize(fs);
}
Update:
Based on your last update, I would guess that either you need to specify an XmlRoot attribute on the class that's acting as your root element (i.e. SalesEnquiry), or the XmlSerializer might be a bit confused that you're referencing an empty namespace in your XML (xmlns='' doesn't seem right).
XmlSerializer does support arrays & lists... as long as the contained type is serializable.
I have found Xsd2Code very helpful for this kind of thing: http://xsd2code.codeplex.com/
Basically, all you need to do is write an xsd file (an XML schema file) and specify a few command line switches. Xsd2Code will automatically generate a C# class file that contains all the classes and properties plus everything needed to handle the serialization. It's not a perfect solution as it doesn't support all aspects of XSD, but if your XML files are relatively simple collections of elements and attributes, it should be a nice short-cut for you.
There's another similar project on Codeplex called Linq to XSD (http://linqtoxsd.codeplex.com/), which was designed to enforce the entire XSD specification, but last time I checked, it was no longer being supported and not really ready for prime time. Thought it was worth a mention, though.
I would like to know what is the fastest and most lightweight technique to convert a fairly large class to XML. The class will have lists and arrays in it. I need to convert all this data to XML
Here is what my application does:
it will get all the information from the database using linq to enties. Then store the data in a class. Then I want to convert this class to XML. When the data is in XML I will send the XML to the browser along with the xsl stylesheet to be displayed to the user. What is the fastest way to do this.
The XmlSerializer actually creates an assembly (with an XmlSerializationWriter) that is custom made to serialize your class. You can look at the generated code by following these steps.
You only pay the price the first time it encounters a new type.
So I think that you should really go with the XmlSerializer, not only for performance, but for maintainability.
You can use a mixin-like serializer class:
public interface MXmlSerializable { }
public static class XmlSerializable {
public static string ToXml(this MXmlSerializable self) {
if (self == null) throw new ArgumentNullException();
var serializer = new XmlSerializer(self.GetType());
using (var writer = new StringWriter()) {
serializer.Serialize(writer, self);
return writer.GetStringBuilder().ToString();
}
}
}
public class Customer : MXmlSerializable {
public string Name { get; set; }
public bool Preferred { get; set; }
}
// ....
var customer = new Customer {
Name = "Guybrush Threepwood",
Preferred = true };
var xml = customer.ToXml();
The fastest way is to write the code for it yourself. That will remove any overhead, like the need to use reflection to read the properties of the object, as you can access the properties directly.
Add a method to the class that returns it's data as XML, either by returning an XDocument, the XML already formatted as a string, or you can pass an XmlWriter to the method.
By "fastest" do you mean you want the approach which will be fastest to develop? Or do you want the approach which will have the fastest execution speed?
If it's the former, I recommend just using .NET's XmlSerializer class: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
Serializing a class to XML output is as simple as:
XmlSerializer serializer = new XmlSerializer(myObject.GetType());
serializer.Serialize(Response.OutputStream, myObject);
And there are various attributes you can decorate your class with to control things like whether individual properties are serialized as elements or attributes, etc.
There's a good FAQ at http://www.devolutions.net/articles/serialization.aspx also
You could use XML serialization, for example:
Foo foo = new Foo();
XmlSerializer serializer = new XmlSerializer(typeof(Foo));
TextWriter writer = new StringWriter();
serializer.Serialize(writer, foo);
string xml = writer.ToString();
The fastest method would depend on the class, because it would be hand-written to take advantage of knowledge of the specifics of that class in ways a more general approach couldn't do.
I'd probably use XmlTextWriter rather than straight to TextWriter though. While the latter would allow for some further savings, these would be minimal compared to the better structure of XmlTextWriter, and you've already sacrificed a good bit in terms of structure and ease of maintenance as it is.
You can always slot in your super-optimised implementation of XmlWriter afterwards ;)
It sounds like a rather convoluted set-up, when you could just display the class's information on a webpage using ASP.NET MVC. Why take the extra two steps of converting it to XML, send it to the browser, and use an XSL stylesheet to display it to the user? It doesn't make sense.
I wrote a program that serialized one simple object graph to XML in different ways:
1. Using XmlSerializer
2. Using hardcoded xml serializer
30,000 documents:
XmlSerializer took : 0.9 sec
Hardcoded serializer took: 0.45 sec
I relied on XmlWriter in both cases and that adds some overhead.
Note that you can instruct Visual Studio to generate the XmlSerializer assembly during compile time in order to reduce the serialization for that first instance (otherwise an assembly is generated in runtime).
If I am dealing with several standard xml formats what would be the best practice way of encapsulating them in C# 3.5? I'd like to end up with something similar to the System.ServiceModel.Syndication namespace.
A class that encapsulates the ADF 1.0 XML standard would be one example. It has the main XML root node, 6 child elements, 4 of which are required IIRC, several required and optional elements and attributes further down the tree. I'd like the class to create, at a minimum, the XML for all the required pieces all the way up to a full XML representation. (Make sense).
With LINQ 4 XML and extension classes, etc, etc, there has to be some ideas on quickly generating a class structure for use. Yes? No? :)
Am not sure if I gave enough details to get one correct answer but am willing to entertain ideas right now.
TIA
XML serialization seems a good approach. You could even use xsd.exe to generate the classes automatically...
EDIT
Note that the class names generated by the tool are usually not very convenient, so you might want to rename them. You might also want to change arrays of T to List<T>, so that you can easily add items where needed.
Assuming the class for the root element is named ADF, you can load an ADF document as follows :
ADF adf = null;
XmlSerializer xs = new XmlSerializer(typeof(ADF));
using (XmlReader reader = XmlReader.Create(fileName))
{
adf = (ADF)xs.Deserialize(reader);
}
And to save it :
ADF adf = ...; // create or modify your document
...
XmlSerializer xs = new XmlSerializer(typeof(ADF));
using (XmlWriter writer = XmlWriter.Create(fileName))
{
xs.Serialize(writer, adf);
}
Why not just follow the pattern of the SyndicationFeed object in the Syndication namespace? Create a class that takes in a Uri to the xml document or just takes in the document fragment.
Then parse the document based on your standards (this parsing can be done using LinqToXml if you wanted to, though regEx might be faster if you are comfortable with them). Throw exceptions or track errors appropriately when the document doesn't pass the specification rules.
If the document passes the parse step then break the pieces of the document out into public getter properties of your object. Then return the fully hydrated object back to the consumer for use
Seems pretty straight forward to me. Is that what you are after or are you looking for something more than this?