Category Archives: Software Development

The DataContractSerializer is a Dirty Little Peeping Tom

I had a problem today with my SelfSerializer class and the DataContractSerializer. I’ve got this test which was throwing an annoying ‘Object graph for type ‘SelfSerializer’ contains cycles and cannot be serialized if reference tracking is disabled’ error:

    <TestMethod>
    Public Sub SelfSerializerSerializationTest_XMLSerializer()
        Try
            Dim token As New SelfSerializer
            Dim dcs As XmlSerializer = New XmlSerializer(GetType(SelfSerializer))
            Dim xml As String = String.Empty
            Using stream As New StringWriter(), writer As XmlWriter = XmlWriter.Create(stream)
                'Serialize the item to the stream using the namespace supplied
                dcs.Serialize(writer, token)
                writer.Flush()
                'Read the stream and return it as a string
                xml = stream.ToString
            End Using
            Debug.Print(xml)
            Dim newToken As SelfSerializer
            Dim sr As New StringReader(xml)
            Dim reader As XmlReader = XmlReader.Create(sr)
            dcs = New XmlSerializer(GetType(SelfSerializer))
            newToken = CType(dcs.Deserialize(reader), SelfSerializer)
            reader.Close()
            sr.Close()
            Assert.IsTrue(newToken IsNot Nothing)
        Catch ex As Exception
            Debug.Print(ex.Message)
            Throw
        End Try
    End Sub

What’s happening internally is that the DataContractSerializer is using reflection to peep into the private parts of my class!

So to prevent this filthy little activity I have to add the DataContract attribute to the SelfSerializer class and IgnoreDataMember to the two private fields I use internally.

Frankly it’s all a bit Benny Hill…

bennyhill

<cue YakketySax music>

Ajax Post a Knockout Stringified Json Object to an ASP.NET MVC5 Controller

Typically there isn’t a simple way to post from JavaScript a Json object as a string and receive it as such in a controller. This is because the model binding system interferes in the background and when it sees a Json-like string attempts to bind it to a model, but if you have not specified a model in your controller function parameter then it turns it into a null even if you specified that you wanted a string. Thanks model binder, you suck.

So the way around it is to create a wrapper model that contains a string into which you can dump your stringified Json object like this:

Public Class JsonViewModel
    Property Json As String = ""
End Class

Here’s the controller with the function that takes the model as a parameter:

 <HttpPost>
Function Save(model As JsonViewModel) As ActionResult
    If model IsNot Nothing AndAlso model.Json.Length > 0 Then
        Debug.Print(model.Json.ToString)
        'TODO: Process data, either of the following ways will work but the second is more obvious
        'Dim json = JsonConvert.DeserializeObject(model.Json)
        'For Each item In json
        ' Debug.Print(item.Name & ": " & item.Value)
        'Next
        Dim dictjson = JsonConvert.DeserializeObject(Of Dictionary(Of String, Object))(model.Json)
        For Each kvp As KeyValuePair(Of String, Object) In dictjson
            Debug.Print(kvp.Key & ": " & kvp.Value.ToString)
        Next
        Return New HttpStatusCodeResult(200)
    Else
        Return New HttpStatusCodeResult(500)
    End If
End Function

Here’s the JavaScript from inside a Knockout ViewModel that posts the stringified Json object:

self.Save = function () {
    var payload = ko.toJSON(self);
    $.ajax("/Home/Save/", {
        type: "POST",
        processData: false,
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify({ Json: payload })
    })
    .done(function (data) {
        alert('Data saved');
    })
    .fail(function () {
        alert('Data not saved.');
    });
};

VB.NET Equivalent of C# typeof

This is one of the tricky bits of C# to VB.NET conversion that I, like others, always forget. Anyway,

typeof(thing)

should be converted to

GetType(thing)

How To Test Command Line Parameters the Easy Way

Sometimes it’s necessary to call a program and pass some command line parameters, this can be difficult to test as the other program may not be under your control or may be a live system. To test calling another program with command line parameters create a text file, name it ‘DisplayCommandLine.bat’, and insert the following text:


@echo off
@echo %*
pause

Then in your calling program simply substitute ‘CommandLine.bat’ for the program name and you’ll soon be able to see exactly what is being passed from one program to the other.

Do You Know Your Message Queue from Your Windows Procedure?

If you’re a Windows developer and don’t know this then you need to learn it, now. Here’s why:

I’ve been examining some legacy code that has a Timer event with some lengthy code that contains DoEvents calls. A simplified version looks something like this:


Private Sub tmrProcess_Timer()
'Run some slow processing code here
DoEvents
'More slow code here
DoEvents
'Lots more slow code and the occasional DoEvents here
If booComplete Then
tmrProcess.Enabled = False
End If
End Sub

The timer has it’s Interval set to 250 and the slow code could take up to thirty or so seconds to complete.

Given that VB6 is single threaded and that timer messages are low priority the question is if it is at all possible for the Timer event to be re-entered during a DoEvents call or will the VB6 runtime block execution of a Timer event if the Timer event is currently executing?

The reference above contains some interesting clues as to the answer. In particular it states that WM_PAINT messages are combined into a single message but there is no mention of whether or not WM_TIMER messages are combined.

So the best way to find out is to write a test program:


Option Explicit

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private Counter As Integer
Private StopTimer As Boolean

Private Sub cmdStart_Click()
txtResults.Text = "Time: " & Format(Now, "HH:mm:ss") & " Start"
Counter = 0
StopTimer = False
tmrTest.Interval = 500
tmrTest.Enabled = True
End Sub

Private Sub cmdStop_Click()
txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Counter: " & Counter & " Stop"
StopTimer = True
End Sub

Private Sub tmrTest_Timer()
Static Index As Integer
Index = Index + 1
Counter = Counter + 1
txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Index: " & Index & " Counter: " & Counter
DoEvents
Sleep 1000
DoEvents
Sleep 1000
DoEvents
txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Index: " & Index & " Counter: " & Counter
If StopTimer = True Then
tmrTest.Enabled = False
txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Stopped"
End If
End Sub

Here’s my test results:

Time: 15:54:38 Start
Time: 15:54:38 Index: 1 Counter: 1
Time: 15:54:40 Index: 1 Counter: 1
Time: 15:54:41 Index: 2 Counter: 2
Time: 15:54:43 Index: 2 Counter: 2
Time: 15:54:43 Index: 3 Counter: 3
Time: 15:54:44 Counter: 3 Stop
Time: 15:54:45 Index: 3 Counter: 3
Time: 15:54:45 Stopped

What I think is happening is that additional calls to the Timer event are being cancelled by the VB6 runtime Windows Procedure so that only one Timer event can run at once. Then when the Timer is cancelled any remaining WM_TIMER messages are either removed from the queue, ignored, or fail silently because the function they are calling is no longer valid.

Because the Windows Procedure is the core of a client program and are not required to be standardized it would be very interesting to compare how different programs, and especially different programming language runtimes, handle the same situation.

Search XML Column as a String Using LIKE

You can search an XML column as a string without using XQuery by converting it to a string and then using LIKE. However as a computed column can’t be part of a WHERE clause you need to wrap it in another SELECT like this:


SELECT * FROM
(SELECT CONVERT(varchar(MAX), [XMLData]) as [XMLDataString] FROM [TABLE_NAME]) this_is_irrelevant
WHERE [XMLDataString] like '%SEARCH_STRING%'

Resolving the dreaded System.ServiceModel.AddressAccessDeniedException error

I had a complex WCF service based solution working on my development PC but due to a problem when installing Windows 8.1 I had to ‘Refresh’ my PC which basically means reinstalling Windows, losing all my applications, but not my documents or data. So I had a few days of sorting out Windows, reinstalling apps and trying to get all my settings back to just the way they were before.

Now that I’ve reinstalled Visual Studio 2012 my project no longer functions correctly. When I debug a unit test the WCF Service Host displays an error:

Please try changing the HTTP port to 8733 or running as Administrator.
System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:8732/Design_Time_Addresses/MyWCFService/Name/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details). —> System.Net.HttpListenerException: Access is denied

Apparently the usual solution to this is to run Visual Studio as administrator. However I’m unable to do that as the architecture we use at work requires us to reference DLLs on a network drive and network drives cannot be accessed when you run a program as administrator (aka elevated).

The other alternative of changing the port to 8733 would require editing every service, re-referencing them and then rebuilding the solution and hoping that it works (unlikely).

After a bit of digging around and research I found out that recent versions of Windows enforce security settings that prevent you from listening to any ports. I’m assuming that when Visual Studio is installed it reserves a port for it’s own use so that you can host and thus debug web services. This was the localhost:8732 port on my development machine but with reinstalling Visual studio it is now localhost:8733, unfortunately all my app.config files in the solution point to port 8732.

However this can be fixed!

Run an elevated command prompt and execute ‘netsh http show urlacl’. This displays the list of reserved ports amongst which I found this:

Reserved URL            : http://+:8733/Design_Time_Addresses/
User: NT AUTHORITY\INTERACTIVE

Which, I’m assuming, is the entry added when Visual Studio was installed.

Executing the following command reserves the 8732 url/port:

‘netsh http add urlacl url=http://+:8732/ user=WORK\Robin’

Restart Visual Studio and all of a sudden my solution works again.

Passing a small object in the querystring

For the current project at work I need to pass some information from an application or website to another website. Rather than storing the state in a database I decided to serialize the state object and pass it, encrypted, in the querystring.

This is the encoding function:


Dim plaintext as String = myState.Serialize
Dim bytes As Byte() = ASCIIEncoding.UTF8.GetBytes(plaintext)
Dim encrypted As Byte() = Encryption.Encrypt(bytes, key)
Dim encodedtext As String = Convert.ToBase64String(encrypted)
Return System.Web.HttpUtility.UrlEncode(encodedtext)

Note that the serialized and encrypted object is url encoded using the System.Web.HttpUtility.

This is the decode function:


Dim decodedtext As Byte() = Convert.FromBase64String(querystring)
Dim decrypted As Byte() = Encryption.Decrypt(decodedtext, key)
Dim plaintext As String = ASCIIEncoding.UTF8.GetString(decrypted)
Dim mystate As New State
mystate.Deserialize(plaintext)
Return mystate

and in C# because I need to practice my skills:


byte[] decodedtext = Convert.FromBase64String(querystring);
byte[] decrypted = Encryption.Decrypt(decodedtext, key);
string plaintext = ASCIIEncoding.UTF8.GetString(decrypted);
State mystate = new State();
mystate.Deserialize(plaintext);
return mystate;

Note that the querystring is not url decoded, this is because the ASP.NET http handler decodes the querystring before it is passed to your code.

Eldritch Coding Horrors, Part 1

I found this terror today in a legacy application.

Program A uses SetWindowLong to hook the message loop for a Windows Form:


Friend Function StartListening() As Boolean
SetWindowLong(m_MappedWndHandle, GWL_WNDPROC, AddressOf WindowProcedure)
End Function

Program A then shells program B. Program B sends a WM_COPYDATA message to program A. Program A intercept the message, reads the data, and then passes the message to the form:


Public Function WindowProcedure(ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If msg = WM_COPYDATA Then
objMapMemoryData.ReadMessage lParam
End If
WindowProcedure = CallWindowProc(objMapMemoryData.GetWindowProcedureAddress, hwnd, msg, wParam, lParam)
End Function

objMapMemoryData.ReadMessage raises an event that is handled by the Form:


Friend Function ReadMessage(ByVal lParam As Long) As Boolean
‘SNIP: Copy memory around
RaiseEvent MapMemoryDataEvent
End Function

Private Sub objMapMemoryData_MapMemoryDataEvent()
‘SNIP: Process event here
End Sub

To Bind or Not To Bind That is the Question

One of the things that VB6 is very good at is late binding. Back in the days before .NET late binding or OLE Automation as it was also known was one of the only ways to do certain tasks such as create reports in Excel, run Word mail merges from databases, or print nicely formatted documents. However there were downsides too. Applications that late bound to DLLs and EXEs had no means to ensure that the target supported the call being made or even that the target was installed on the PC. This allowed difficult to debug problems to creep into your program.

 So the best solution to late binding problems was to early bind to any DLLs that you wanted to use. This way you could ensure that the interface was correct and that the DLL was installed on the system. However this led to another problem: DLL Hell. When an updated DLL was installed your system had to keep track of each version of the DLL and make sure that the right program called the right version. If a DLL was relied upon by a lot of programs and was regularly updated then a new installation could mess up an old program.

 So .NET included ‘xcopy’ installation – simply include the right version of each referenced DLL in the same directory as the application and late binding became something that only ‘bad’ programmers did. Early bound DLLs also need to be loaded by the system when your program initiates.

 The thing is that late binding solves a certain class of problem, one that often occurs in legacy applications. When adding new features supported by a DLL or refactoring old features to use new DLLs early binding to the DLL can cause problems with your installation program/routine, especially where DLL Hell issues have been previously overcome or there are a large number of support DLLs required for the application.

 So a simple approach to enhancing or refactoring an old application is to develop with the references early bound and then switch to late binding and copy the required DLLs into either the application directory or another suitable location.