Convert linq.Xelement to stream for XMLTextReader - vb.net

I am producing an XML file in my unit test using
Public Sub rssParserTest
Dim Const rssUri as String = "rssTestFile.xml"
Dim xmlFile = <rss version="2.0">
...
</rss>
xmlFile.save(rssUri)
rssParser(rssUri)
End Sub
and consuming the uri with an XMLTextReader
Public Sub rssParser(ByVal rssUri as string)
Dim rssXml = New XmlTextReader(rssUri)
rssXml.read
...
End Sub
I want to remove the unit test dependency on a physical file and use a stream instead but my efforts so far have come to nought. (Is this best practise?)
I am using NMock2 for mocking if I should be doing something with that.

Rather than force an XmlTextReader via a stream, if you just nead an XmlReader you can just use XNode.CreateReader. That's a much simpler approach than saving to a stream, unless your API forces you to use a stream or an XmlTextReader.

xmlFile is an XDocument, which can be saved into a MemoryStream, see the following SO question for details:
Convert XDocument to Stream (The code samples are in C#, but the .NET API methods used are the same.)
You can then make your method accept a generic Stream, which can then be a MemoryStream (in the unit test) or a FileStream.

Related

Can somebody give me an example of getting the content of a page from a URL in vb.net for windows 8?

I am very new to vb/.net and I'm trying to do something that I can do easily in classic vb. I want to get the source html for a webpage from the URL.
I'm using vb.net in Visual Studio Express for Windows 8.
I've read loads of stuff that talk about HttpWebRequest, but I can't get it to work properly.
I did at one point have it returning the html header, but I want to content of the page. Now, I can't even get it back to giving me the header. Ultimately, I want to process the html returned which I'll do (to begin with) the old-fashioned way and process the returned html as a string, but for now I'd like to just get the page.
The code I've got is:
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create(New Uri(URL))
txtHTML.Text = request.GetRequestStreamAsync().ToString()
Can anyone help me with an example to get me going please?
You're trying to use an Async method in a synchronous way, which won't make any sense. If you're using .NET 4.5, you can try marking the calling method with Async and then using the Await keyword when calling GetRequestStreamAsync.
Public Sub MyDownloaderMethod()
Dim URL As String = "http://www.crayola.com/"
Dim request As System.Net.HttpWebRequest
= System.Net.HttpWebRequest.Create(New Uri(URL))
' Use the Await keyword wait for the async task to complete.
Dim response = request.GetResponseAsync()
txtHTML.Text = response.GetResponseStream().ToString()
End Function
See the following MSDN article for more information on async programming with the Await keyword: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
Edit
You are receiving your error because you're trying to get the Request stream (what you send the server), and what you really want is the Response stream (what the server sends back to you). I've updated my code to get the WebResponse from your WebRequest and then retrieve the stream from that.
Public Shared Function GetWebPageString(ByVal address As Uri) As String
Using client As New Net.WebClient()
Return client.DownloadString(address)
End Using
End Function
There is also DownloadStringAsync if you don't want to block
request.GetRequestStreamAsync() is probably not a method. I think you're cribbing code from a site where someone wrote their own add-on methods to HttpWebRequest. Try request.GetResponse() to return a response object, then in the response object you can inspect the stream and convert it to text if you need to.
This worked for me in VB.Net 4.5
Public Async Sub GetHTML()
Dim PageHTML as string
Dim client As New HttpClient
Dim getStringTask As Task(Of String) = client.GetStringAsync(PageURL)
PageHTML = Await getStringTask
MsgBox(PageHTML)
End Sub

Magento API SOAP v1 and VB.NET

I'm using VB.NET to communicate with Magento via the API SOAP v1. I had it working fine until I got to a call that needed an associative array. I've tried dictionaries, hashtables, custom types, etc. I did read hashtables and dictionaries are not serializable. So I tried the custom type/object/class. Below is the error I received:
The type XXXX was not expected. Use the Xmlinclude or SoapInclude attribute to specify types that are not known statically.
So I've read a lot of posts in regards to the above error and I can't get anything to work. The error seems at least to say what I'm trying is possible if I do it right, but maybe that is not the case. I don't know much about SOAP, but I can see this never working since the web service might not know how to handle the object.
So my question is if it's possible to send a custom object to the Magento API. Or more broadly is it possible to get SOAP v1 to work with VB.NET. I know v2 is an option but I'm pretty familiar with v1 and already having it working in VB.NET other than this scenario.
Answering a question you didn't ask — but have you considered using the XML-RPC adapter for the V1 API? It exposes the same exact methods as the SOAP API, but since XML-RPC doesn't have the same strong concept of types that SOAP does you may be able to get a generic object through from .NET (said without being that familiar with .NET SOAP or XML-RPC libraries)
It took a lot of digging, but I have it all working. To start I used the PHP SoapClient and noted how it formed associative arrays in the soap request. You can trace requests and responses, pretty handy. From there I wrote my own soap client in VB.NET using a WebRequest object. In doing so I have full control over the xml being sent to the API.
Again the reason I went down this road is ultimately V2 was not working for me. For some reason not all parameters were making it to the API. That and the fact I'm pretty comfortable with V1 too. I've written several custom APIs.
I apologize for the brevity, but there is a lot that went into this. Probably most of my time was hitting multiple dead ends. If anyone wants specifics feel free email me.
EDIT:
Here is the php code I used to see how I needed to format the requests:
$client = new SoapClient('http://www.site.com/index.php/api/soap/?wsdl',array('trace' => TRUE));
$session = $client->login('user','api-key');
echo $client->__getLastRequest() ."\n\n";
echo $client->__getLastRequestHeaders() ."\n\n";
echo $client->__getLastResponse() ."\n\n";
echo $client->__getLastResponseHeaders() ."\n\n";
$result = $client->call($session, 'cataloginventory_stock_item.list','393');
echo $client->__getLastRequest() ."\n\n";
echo $client->__getLastRequestHeaders() ."\n\n";
var_dump($result);
$client->endSession($session);
Below is how to send the request using VB.NET. You will need to construct the XML/SOAP body using the php above as a guide. I made a class per API call which output the needed XML. You will need System.Net, System.Xml & System.IO. I used getSoapHeader() because there is some common XML that goes into a request. See next code section for more details:
Private Function makeSoapRequest(ByVal soapBody As String) As String
Dim req As WebRequest = WebRequest.Create(_soap_url)
Dim xml As String
xml = getSoapHeader() & soapBody
Dim buffer() As Byte = System.Text.Encoding.UTF8.GetBytes(xml)
req.ContentType = "text/xml; charset=utf-8"
req.Method = "POST"
req.Headers.Add("SOAPAction", "urn:Mage_Api_Model_Server_HandlerAction")
req.ContentLength = buffer.Length
Dim st As System.IO.Stream = req.GetRequestStream
st.Write(buffer, 0, buffer.Length)
st.Close()
Dim response As WebResponse
Try
response = req.GetResponse
Catch ex As WebException
response = ex.Response
End Try
st = response.GetResponseStream()
Dim reader As New StreamReader(st)
Dim responseFromServer As String = reader.ReadToEnd()
makeSoapRequest = responseFromServer
response.Close()
st.Close()
End Function
Below is the getSoapHeader() function. As noted the ns2 portion is only needed if you are using type="ns2:Map" which is what I needed for associative arrays:
Private Function getSoapHeader() As String
'ns2 is not always needed
getSoapHeader = "<?xml version=""1.0"" encoding=""UTF-8""?><SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:ns1=""urn:Magento"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:SOAP-ENC=""http://schemas.xmlsoap.org/soap/encoding/"" xmlns:ns2=""http://xml.apache.org/xml-soap"" SOAP-ENV:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/""> " & vbCrLf
End Function

Optimizing HttpWebResponse - GetResponse

I'm using the following lines of code to read the response of an asynchronous HttpWebRequest. This seems to be the largest amount of time spent in a particular operation. Is there anything I can optimize here?
System.Net.HttpWebResponse oResp =(System.Net.HttpWebResponse)oReq.EndGetResponse(oResult);
oResp = (HttpWebResponse)oReq.GetResponse();
StreamReader oStreamReader = new StreamReader(oResp.GetResponseStream());
string sResponse = oStreamReader.ReadToEnd();
...goes on to make an XmlDocument, append some more XML to it, then perform an XSL transform.
Creating the Connections:
HttpWebRequest oReq;
oReq = (HttpWebRequest)WebRequest.Create(sUrl + sQueryString);
oReq.ContentType = sContentType;
oReq.Method = "POST";
oReq.ContentLength = aBytes.Length;
Stream oStream = oReq.GetRequestStream();
oStream.Write(aBytes, 0, aBytes.Length);
oStream.Close();
AsyncState oState = new AsyncState(oReq);
return oReq.BeginGetResponse(fCallBack, oState);
I found one major improvement to the scheme I was using. Rather than using the StreamReader and ReadToEnd to get the Stream into a string, only then to convert it into an XmlDocument. I skipped the middle man and converted the Stream directly into a XmlDocument.
This left me with another problem though, I had to change the parent of the XmlDocument to fit my Xslt (there are a great many and they all expect the structure I had). See How can I add new root element to a C# XmlDocument? for that fix.
This has given me a roughly 2/3 decrease in the time taken to process the results of the webservice call, and a great decrease in the amount of memory used. In the previous version, the response xml was in memory two different times (maybe three if the stream counts)!
In addition, removing the extra GetResponse seemed to help.
using (HttpWebResponse oResp = (HttpWebResponse)oReq.EndGetResponse(oResult))
{
oXml.Load(oResp.GetResponseStream());
XmlNode oApiResult = oXml.RemoveChild(oXml.DocumentElement);
oXml.LoadXml(sOtherXml);
oXml.DocumentElement.AppendChild(oApiResult);
}

Return more than a single value from a WebService

I have to return a lot of values back to my windows application from my webService. But how would I return more than just a single string/int/boolean from my WebService to my Application. How would I return a collection, keyValuePair, or even better, a DataSet? Or is this just imposible?
thank you :)
any serializable class can be returned from a web service
If your webservice is written in ASP.NET it's as simple as setting the return type from your webservice to be the more complex type. Most serializable types are supported.
The best method I've used with webservices is to return XML as a string. This way there are no compatability issues and parsing the XML is easy enough.
Along the same lines as returning XML, if you're returning to javascript code, you may want to consider returning your complex type as serialized in JSON.
Here is an extension method which makes this really easy...
<Extension()> Public Function ToJSON(Of T As Class)(ByVal target As T) As String
Dim serializer = New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(T))
Using ms As MemoryStream = New MemoryStream()
serializer.WriteObject(ms, target)
ms.Flush()
Dim bytes As Byte() = ms.GetBuffer()
Dim json As String = Encoding.UTF8.GetString(bytes, 0, bytes.Length).Trim(Chr(0))
Return json
End Using
End Function
Then in your data service, you can simply call
Return MyObject.ToJSON

How do I unit test object serialization/deserialization in VB.NET 1.1?

I am looking for example code that provides a unit test to serialize and deserialize an object from a memory stream. I have found examples using C# 2.0, however my current project uses VB.NET 1.1 (don't ask me why...), so the solution can not use generics. I am also using the NUnit framework for the unit tests.
Thanks!
This is the pattern I've settled upon:
<Test()> _
Public Sub SerializationTest()
Dim obj As New MySerializableObject()
'Perform additional construction as necessary
Dim obj2 As MySerializableObject
Dim formatter As New BinaryFormatter
Dim memoryStream As New MemoryStream()
'Run through serialization process
formatter.Serialize(memoryStream, obj)
memoryStream.Seek(0, SeekOrigin.Begin)
obj2 = DirectCast(formatter.Deserialize(memoryStream), MySerializableObject)
'Test for equality using Assert methods
Assert.AreEqual(obj.Property1, obj.Property1)
'etc...
End Sub
NUnit has built in support for this which makes it quite a bit easier:
Dim obj As New MySerializableObject()
Assert.That(obj, Is.BinarySerializable)
Or for xml:
Dim obj As New MySerializableObject()
Assert.That(obj, Is.XmlSerializable)
If all you want to do is to ensure that they are serializable then all you should have to do it to do a serialization of an object and make sure no XmlSerializationException was thrown
[Test]
public void ClassIsXmlSerializable()
{
bool exceptionWasThrown = false;
try
{
// .. serialize object
}
catch(XmlSerializationException ex)
{
exceptionWasThrown = true;
}
Asset.IsFalse(exceptionWasThrown, "An XmlSerializationException was thrown. The type xx is not xml serializable!");
}
Hmm...so you are trying to write a unit test for serialization? Or for streams? This is hopefully done by MS already...but if you don't trust or implement something on your own...you could just fill object with some data, save it, restore it, and check if the fields values are in place?