I have 2 specific questions with regards to passing a System.IO.Stream (from a method) and deserialization into object (another method).
XML Response I get from a WebRequest (please note there are no root tags)
<?xml version="1.0" encoding="UTF-8"?>
<response id="-2d953936:14174bb0cf3:-5213">
<date>2013-10-01 12:01:55.532999</date>
<status>
<current>open</current>
<next>after</next>
<change_at>16:00:00</change_at>
</status>
<message>Market is open</message>
<unixtime>1380643315</unixtime>
</response>
Method 1 - ResponseMethod - Currently returning string
private static string GetResponse(HttpWebRequest request)
{
var v_Response = request.GetResponse();
var v_DataStream = v_Response.GetResponseStream();
var v_Reader = new System.IO.StreamReader(v_DataStream);
var x_XMLResponse = v_Reader.ReadToEnd();
//Close all Stream logic
v_Reader.Close(); v_DataStream.Close(); v_Response.Close();
return x_XMLResponse;
}
Method 2 - Convert the XML to an object
// I would use XDocument and Lin2XML to get my typed object - for example MarketStatus
Questions are:
I am currently passing string from Method 1. That doesnt help me in deserializing from XML to object. Should I be passing the return value as StreamReader and then use that as an input into method 2 to get my typed object. Is that a standard approach or there are better ways to this?
My ultimate objective is that the return value from second method should be an object.
Additional Note:
The reason this functionality is broken into 2 methods because I want the web response method and deserailization separate for testing purposes.
I don't have an XSD but have created a MarketStatus Class
Any code snippets/suggestions will really appreciate
We typically use a generic method, similar to the following (simplified for posting), which uses the XMLSerializer to deserialize an XML string representation into the corresponding object.
public T ReturnObjectfromXml<T>(string xmlForm)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
StringReader sr = new StringReader(xmlForm);
XmlTextReader xts = new XmlTextReader(sr);
return ((T)xs.Deserialize(xts));
}
Hope this helps.
Regards,
It looks like you are doing some type of message passing. You will be better off using WCF or ASP.NET Web API instead of rolling your own infrastructure code (to serialize and de-serialize).
To answer question 1: No, it is better to return a string and dispose of the reader as soon as you are done with it. See When should I dispose my objects in .NET?
Comment on note 1: In most cases, you wouldn't want to unit test the serialization/deserialization.
Related
I am trying to use XML for my GeneralMappingStrategy in Asternet. I have my program working fine using List
such as:
agiServer.MappingStrategy = new GeneralMappingStrategy(
new List<ScriptMapping>()
{
new ScriptMapping() {
ScriptName = "testIVR",
ScriptClass = "Asterisk_Test.testIVR",
}
});
But I'd rather have it read an XML file as it says it can do in the documentation, however it does not seem to say anywhere what the XML format is required.
I have tried:
string pathtoxml = "test.xml";
agiServer.MappingStrategy = new GeneralMappingStrategy(pathtoxml);
With my XML as:
<?xml version="1.0"?>
<ScriptMapping>
<ScriptName>testIVR</ScriptName>
<ScriptClass>Asterisk_Test.testIVR</ScriptClass>
</ScriptMapping>
As a complete guess, seemed to make sense, but this won't compile, I get errors of:
System.InvalidOperationException: 'There was an error reflecting type 'System.Collections.Generic.List`1[AsterNET.FastAGI.MappingStrategies.ScriptMapping]'.'
Does anyone happen to know how to do this?
It appears that there was an issue with the Aster.NET library, I've now submitted the fix and it's been accepted. For anyone who has an issue on this in the future, the XML format is:
<?xml version="1.0"?>
<ArrayOfScriptMapping xmlns:xsi="w3.org/2001/XMLSchema-instance"; xmlns:xsd="w3.org/2001/XMLSchema">
<ScriptMapping>
<ScriptName>testIVR</ScriptName>
<ScriptClass>Asterisk_newTest.testIVR</ScriptClass>
</ScriptMapping>
</ArrayOfScriptMapping>
I need to read content of message in WCF project like
var messageContent = Encoding.UTF8.GetString(OperationContext.Current.RequestContext.RequestMessage.GetBody<byte[]>());
But in result I got an error:
Expecting element 'base64Binary' from namespace
'http://schemas.microsoft.com/2003/10/Serialization/'.. Encountered
'Element' with name 'Human', namespace
'http://numans.hr-xml.org/2007-04-15'.
Can you please suggest me what Im doing wrong?
Content that I'm sending are:
<Human xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://numans.hr-xml.org/2007-04-15">
<HumanId>
<guid>c2ee9a7e-c7a8-48e0-910b-47c2012bfa8e</guid>
</HumanId>
...
</Human>
Also I tried to read content like:
var messageContent = OperationContext.Current.RequestContext.RequestMessage.ToString();
Result of messageContent:
...stream...
GetBody<T> is used to deserialize the message body as type T. So when you call GetBody<byte[]>(), the deserializer expects base64-encoded binary data but finds the <Human> element.
If you only want to read the message body as string, use GetReaderAtBodyContents which returns an XmlDictionaryReader, at which you can use ReadOuterXml().
If you want to read the body as typed content, create a Human class from its XML representation and use GetBody<Human>().
I'm currently testing in visual studio 2010. I made a client and server which both will connect through UdpClient.
I want to send an object from the client to the server. I have two methods to convert the object to bytes and to convert it to an object. Now, when I test my application I can't convert it back to an object once received on the server
My server sees that the object is received and tries to convert it from bytes to the object but this gives an error.
System.Runtime.Serialization.SerializationException was unhandled Message=Unable to find assembly
This seems okay because both applications are in a different namespace...
These are my methods to convert; Both the same on client and server
public byte[] ToBytes() {
using (MemoryStream stream = new MemoryStream()) {
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
byte[] byteRij = new byte[1024];
stream.Read(byteRij, 0, (int)stream.Length);
return byteRij;
}
}
public static Datagram ToDatagram(byte[] rij) {
using (MemoryStream stream = new MemoryStream()) {
stream.Write(rij, 0, rij.Length);
stream.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
return (Datagram)formatter.Deserialize(stream);
}
}
How can I resolve this?
Thanks in advance
You need to put all classes that are serialized in a class library project. Use that library in both the server and the client.
Also note that UDP is not reliable. There is no guarantee that your messages arrive at all.
BinaryFormatter is deeply tied to the type metadata. It is not a good choice here, since you have different types. Actually IMO it isn't a good choice anyway :) It is not very version tolerant, and is not portable.
I will openly recommend protobuf-net here (disclosure: I wrote it). It is free OSS, but uses google's protobuf format to fix all the BF problems. It is trivial to setup and use, is faster, and has smaller output than BinaryFormatter. Since it is contract-based you can have different types at each end, as log as they agree on the contract (matching field-numbers etc).
For example:
[ProtoContract]
public class Foo {
[ProtoMember(1)]
public string X {get;set;}
[ProtoMember(2)]
public int Y {get;set;}
}
And then just use ProtoBuf.Serializer.Serialize(stream, object) to write the data.
You can also work without attribute if you need, it takes a little more setup, but not much.
You may be experiencing problems with unsatisfied dependency. This may be caused by different namespaces or by trying to serialize external component, which isn't installed on server.
Say: you send object of type MyApp1.MyFoo.
Class MyFoo is also defined in your server, but as MyApp2.MyFoo (which is quite silly and means that you have to fix your design). Server doesn't know how to create an object of MyApp1.MyFoo because it isn't smart enough to find out that he also has this class defined, but named MyApp2.MyFoo.
You should use same namespaces. This is what they're for. Also, they make handling dependencies easier. And MyApp.Server talking to MyApp.Client looks nice ;).
I hope you get the point.
I'm trying to create an XML document to return through a web service, and am quite stumped. I'm still pretty new at XML itself, so I'm trying to learn as I go. The error I'm getting is
object reference not set to an
instance of an object.
The code works by calling a constructor, taking in the request document and parsing it to the response. I have the format of both the request and the response, and just need to be able to send it back.
Code:
XmlTextReader xml_read = new XmlTextReader(HttpContext.Current.Request.MapPath("/ap/aitcXMLConfirmationRequest.xml"));
XmlDocument xml_doc = new XmlDocument();
xml_doc.Load(xml_read);
xml_read.Close();
//Do some stuff.
int int_dtl = 1;
//Builds the list of Confirmation items.
XmlNodeList nodelst_cnfrm = p_transdoc.SelectNodes("//Request/OrderRequest/ItemOut");
foreach (XmlNode node in nodelst_cnfrm)
{
XmlNode node_cnfrm_itm = this.CreateElement("ConfirmationItem");
//Do some other stuff here
}
xml_doc.ImportNode(node_cnfrm_itm,true);
root.AppendChild(xml_doc); //Error generated here.
this.AppendChild(root);
But it's giving me the aforementioned error. Can anyone help out? I'm not understanding how there is no instance of an object, if I have been manipulating it before the AppendChild request.
Any ideas?
With respect to NullReferenceExceptions in general, you should just put a break point (typically F9) on that line and start the Debugger. Once that line is hit, inspect the variables and confirm that one is in fact null.
In your case, it should be pretty obvious that root is null (given the code successfully uses xml_doc). At that point, find the places where root is supposed to be set and investigate why that isn't happening.
I'm currently working on a project that involves a lot of XSLT transformations and I really need a debugger (I have XSLTs that are 1000+ lines long and I didn't write them :-).
The project is written in C# and makes use of extension objects:
xslArg.AddExtensionObject("urn:<obj>", new <Obj>());
From my knowledge, in this situation Visual Studio is the only tool that can help me debug the transformations step-by-step. The static debugger is no use because of the extension objects (it throws an error when it reaches elements that reference their namespace). Fortunately, I've found this thread which gave me a starting point (at least I know it can be done).
After searching MSDN, I found the criteria that makes stepping into the transform possible. They are listed here. In short:
the XML and the XSLT must be loaded via a class that has the IXmlLineInfo interface (XmlReader & co.)
the XML resolver used in the XSLTCompiledTransform constructor is file-based (XmlUriResolver should work).
the stylesheet should be on the local machine or on the intranet (?)
From what I can tell, I fit all these criteria, but it still doesn't work. The relevant code samples are posted below:
// [...]
xslTransform = new XslCompiledTransform(true);
xslTransform.Load(XmlReader.Create(new StringReader(contents)), null, new BaseUriXmlResolver(xslLocalPath));
// [...]
// I already had the xml loaded in an xmlDocument
// so I have to convert to an XmlReader
XmlTextReader r = new XmlTextReader(new StringReader(xmlDoc.OuterXml));
XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddExtensionObject("urn:[...]", new [...]());
xslTransform.Transform(r, xslArg, context.Response.Output);
I really don't get what I'm doing wrong. I've checked the interfaces on both XmlReader objects and they implement the required one. Also, BaseUriXmlResolver inherits from XmlUriResolver and the stylesheet is stored locally. The screenshot below is what I get when stepping into the Transform function. First I can see the stylesheet code after stepping through the parameters (on template-match), I get this:
If anyone has any idea why it doesn't work or has an alternative way of getting it to work I'd be much obliged :).
Thanks,
Alex
I'm not sure about usage of extension objects but as I understand your problem is with debugging of XSLT transformation in code in VS2010.
Here is the function that we use to debug XSLT transformation:
public string ApplyTransformation(string inputFilePath, string xsltFileContent)
{
XslCompiledTransform transform = new XslCompiledTransform(debugEnabled);
File.WriteAllText(xsltTempFilePath,xsltFileContent);
transform.Load(xsltTempFilePath, XsltSettings.TrustedXslt, new XmlUrlResolver());
XmlReader reader = XmlReader.Create(inputFilePath);
StringWriter output = new StringWriter();
XmlWriter writer = XmlWriter.Create(output,transform.OutputSettings);
transform.Transform(reader,writer);
return output.ToString();
}
Unfortunately, there is a bug with VS2010 XSLT debugger which will make your debugging experience worse than in VS2008.
Consider debugging using XML Spy XSLT debugger. It works for me all the time.