System.Net.Http Error After Visual Studio 15.8.1 (2017) Update

Today we started getting an error from three web applications.  Two were web services and one was an ASP.NET MVC website.  The error was:

Could not load file or assembly ‘System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

The error was occurring on this standard line in the global.asax file:

WebApiConfig.Register(GlobalConfiguration.Configuration)

Looking at the trace statements on the error page, there was a mention of a binding redirect, which I recall seeing in the web.config of the site.  That section in the web config looked like:

<runtime>
    <assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentassembly>
        <assemblyidentity culture="neutral" publickeytoken="b03f5f7f11d50a3a" name="System.Net.Http">
          <bindingredirect newversion="2.2.29.0" oldversion="0.0.0.0-2.2.29.0">
          </bindingredirect>
        </assemblyidentity>
      </dependentassembly>
    </assemblybinding>
</runtime>

This config block had been in place since December, 2015.  The block seems to have been added by a NuGet package at the same time, possibly with a Framework version upgrade.

However it originally ended up there, removing the config block allowed the sites to launch again.  It’s unknown why this started happening after a Visual Studio upgrade.

Uneventful

After reading the post about events and AddHandler and tracking references and hanging objects, you might be a little concerned about using events at all, maybe because of the added code or the housekeeping.  If so, you can consider another way of doing event-type behavior using Delegates.

Delegates can be used many different ways.  This particular way might be a little different than what you’ve previously seen.  The general concept is to keep a variable holding all the delegates to be called for an event.  This variable (as a delegate itself) can be invoked at any time, and more importantly, can be cleared at any time.

Reusing some old code from the previous post, we still have our HangingObject class and we now have this method to build the objects and call their internal method:

    Private Sub UsingDelegate()
        Dim o As HangingObject

        HelloList = [Delegate].RemoveAll(HelloList, HelloList)
        
        For i As Integer = 1 To 5
            o = New HangingObject
            HelloList = [Delegate].Combine(HelloList, New SayHelloDelegate(AddressOf o.SayHello))

        Next

        HelloList.DynamicInvoke(Nothing)

    End Sub

And at the form level, we have the delegate sub definition and the delegate variable holding all the calls.

    Public Delegate Sub SayHelloDelegate()
    Dim HelloList As [Delegate] = Nothing

So what’s different?  We’ve changed the event declaration to a Delegate Sub declaration; we’ve added a variable to hold all the event subscriptions; instead of using AddHandler, we use Delegate.Combine to register the event subscription; and instead of RaiseEvent, we use DynamicInvoke.  There’s not much more or less, but everything is different.  The list of subscribers is accessible now through the variable HelloList, which is a huge benefit.

The two interesting parts of this code are the shared methods on the Delegate class: Combine and RemoveAll.  The delegate itself (HelloList) contains a list of invocation targets, similar to subscribers of an event.  The Combine method merges the specific SayHelloDelegate invocation list with the generic HelloList invocation list, resulting in one list of all the targets.  Calling the DynamicInvoke method performs a .Invoke on all the delegates in the invocation list.  Simple and magical.

However, because HelloList is declared at the form level, it persists between calls and can suffer the same issues as the AddHandler method.  The nice thing is that you can clear the invocation list by using RemoveAll, or you can just set the variable to Nothing.  If HelloList was defined within the method instead of the form, it would be cleared at the end of the method, unlike the AddHandler method, where the event is declared at the form level.

It’s good to know a lot of different ways to do something, just in case.  Another tool in the coding toolbox.

ByVal, ByRef, Structure, Class, ugh.

In another post I referred to this topic as a phenomena.  That’s pretty over-dramatic.  But there are some important rules and guidelines for types in .NET and until you know why things happen as they do, it seems like voodoo.  So here’s an all-in-one example to clear it all up.  But, be warned that it’s going to be very confusing until it “clicks”.

A brief prelude:  .NET has two variable types, value types and reference types.  A value type is stored on the stack, is generally small, and contains its actual data.  A reference type is stored on the heap, has an unknown or variable size, and contains pointers to the actual data.  .NET also has two definitions that utilize these types: Structures and Classes.  Structures are value types and Classes are reference types.

Method calls support two parameter keywords: ByVal and ByRef.  ByVal passes the parameter data to the method by value, in other words, it sends the values to the method.  ByRef sends the parameter data to the method by reference, it sends a reference to the parameter data.  The thing that is most misunderstood is that if the parameter type is a reference type (a class) and it is sent ByVal, the value is a copy of the reference.  When the parameter type is a value type (a structure) and is sent ByVal, the value is a copy of the value – a real copy.  Here’s a quick real-world summary of method/parameter behavior:

  • A class passed ByVal – the method works on the original (kind of)
  • A structure passed ByVal – the method works on a copy
  • A class passed ByRef – the method works on the original
  • A structure passed ByRef – the method works on the original

If you’re still following, you might notice some vagueness in the most common method call type: classes passed ByVal.  This will be explained after a demo of these different combinations.  So for demonstration, we create a Class and a Structure with a public field:

Public Class NameClass
    Public Name As String

    Public Sub ChangeName()
        Name &= " (changed)"
    End Sub

End Class

Public Structure NameStructure
    Public Name As String

    Public Sub ChangeName()
        Name &= " (changed)"
    End Sub

End Structure

A method is in each to modify the internal state.  This will prove whether we are working on a copy or the original.  Next, we make a class that uses these objects and modifies them in private methods with parameters passed in various combinations:

Public Class PersonClass
    Public Name1 As New NameClass
    Public Name2 As New NameStructure

    Public Sub UpdateNames()
        Name1.Name = "Class Name"
        Name2.Name = "Structure Name"

        Debug.WriteLine("Name1 before ByVal: " & Name1.Name)
        UpdateClassByVal(Name1)
        Debug.WriteLine("Name1 after ByVal: " & Name1.Name)

        Debug.WriteLine("Name2 before ByVal: " & Name2.Name)
        UpdateStructureByVal(Name2)
        Debug.WriteLine("Name2 after ByVal: " & Name2.Name)

        Debug.WriteLine("Name1 before ByRef: " & Name1.Name)
        UpdateClassByRef(Name1)
        Debug.WriteLine("Name1 after ByRef: " & Name1.Name)

        Debug.WriteLine("Name2 before ByRef: " & Name2.Name)
        UpdateStructureByRef(Name2)
        Debug.WriteLine("Name2 after ByRef: " & Name2.Name)

    End Sub

    Private Sub UpdateClassByVal(ByVal item As NameClass)
        item.ChangeName()
    End Sub

    Private Sub UpdateStructureByVal(ByVal item As NameStructure)
        item.ChangeName()
    End Sub

    Private Sub UpdateClassByRef(ByRef item As NameClass)
        item.ChangeName()
    End Sub

    Private Sub UpdateStructureByRef(ByRef item As NameStructure)
        item.ChangeName()
    End Sub

End Class

So, after instantiating this class and calling UpdateNames, we get the following results:

Name1 before ByVal: Class Name

Name1 after ByVal: Class Name (changed)

Name2 before ByVal: Structure Name

Name2 after ByVal: Structure Name

Name1 before ByRef: Class Name (changed)

Name1 after ByRef: Class Name (changed) (changed)

Name2 before ByRef: Structure Name

Name2 after ByRef: Structure Name (changed)

In the same order as the bullet list above, we can see that Name2 (the structure) passed ByVal did not change, showing that the method was working on a copy.  Everything else remained changed after leaving the method call, showing they were working on the original.

Now to add confusion and clarity to the ambiguity of passing classes ByVal…

When you pass a class to a method ByVal, you are sending a copy of the reference.  Everything that is inside that class is a reference as well, so when you change a property, it’s still changing the same property in the original – they share the same reference.  This essentially is like working on the original.  However, you cannot change the class itself.  What?

Here’s another bit of code to add to PersonClass to illustrate:

    Public Sub UpdateObjects()
        Name1.Name = "Class Name"

        Debug.WriteLine("Name1 before ByVal: " & Name1.Name)
        UpdateClassObjectByVal(Name1)
        Debug.WriteLine("Name1 after ByVal: " & Name1.Name)

        Debug.WriteLine("Name1 before ByRef: " & Name1.Name)
        UpdateClassObjectByRef(Name1)
        Debug.WriteLine("Name1 after ByRef: " & Name1.Name)

    End Sub

    Private Sub UpdateClassObjectByVal(ByVal item As NameClass)
        item = New NameClass
        item.Name = "Replaced Class"
    End Sub

    Private Sub UpdateClassObjectByRef(ByRef item As NameClass)
        item = New NameClass
        item.Name = "Replaced Class"

    End Sub

What this code does is try to reassign the value of Name1 to a new instance.  When you call UpdateObjects, you will see you can’t change the instance of Name1 when the parameter is passed ByVal, but you can when it is passed ByRef.

Name1 before ByVal: Class Name

Name1 after ByVal: Class Name

Name1 before ByRef: Class Name

Name1 after ByRef: Replaced Class

Again, because ByVal passes a copy of the reference where ByRef passes the actual reference.  If you reassign the value when it is passed ByVal, you’re only reassigning to a copy, which has no effect on the original.

In real-world usage, using ByVal with classes is going to work for you 99% of the time, but you need to understand why and how things work to handle that odd 1% of cases and avoid crazy workarounds.

Why Won’t You Go Away?!

All .NET developers should know that .NET is pretty reference-happy.  There’s an interesting phenomena with Structures and Classes that I can illustrate later, but the issue I wanted to point out here involves references and garbage collection.  As we know, .NET manages object cleanup through the garbage collector when there are no more references to the object.  This is kind of nice because you can let objects just fall out of scope and the GC will take care of everything.  That is, if nothing else has a reference to those objects.

One thing to pay special attention to is event handlers.  These create references and can keep objects alive MUCH longer than you want; maybe for the running life of the application.  As a potential scenario, you have a form with a form-level event.  That form has a method that creates some objects that listen for that event.  The method does its stuff and finishes.  You call the method again and suddenly you have twice as many responses to the event.  The objects you set up from the first run still exist and listen for that event.

Here’s some demo code to illustrate this.

The class that responds to the event:

Public Class HangingObject

    Public Sub SayHello()
        MsgBox("Hello from " & Me.GetHashCode.ToString)
    End Sub

End Class

The method that creates the objects and raises the event:

    Private Sub ShowHanging()
        Dim o As HangingObject

        For i As Integer = 1 To 5
            o = New HangingObject
            AddHandler Me.SayHelloEvent, AddressOf o.SayHello

        Next

        RaiseEvent SayHelloEvent()

    End Sub

And the form-level event:

Public Event SayHelloEvent()

So if you call ShowHanging, you get 5 Messageboxes.  If you call it again, you get 10, and so on.

The reason for this is the AddHandler statement.  AddHandler creates a reference to the instance of the object “o” and stores it with the form-level event SayHelloEvent.  When do these references get removed?  When the form is disposed.  If that form is the main form of the application, that will be when the application ends.

Can you get around this?  Maybe by implementing Dispose and disposing the objects?

Public Class HangingDisposableObject
    Implements IDisposable

    Public Sub SayHello()
        MsgBox("Hello from " & Me.GetHashCode.ToString)
    End Sub

    Private disposedValue As Boolean
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
            End If

        End If
        Me.disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

End Class

    Private Sub ShowHanging()
        Dim o As HangingDisposableObject

        For i As Integer = 1 To 5
            o = New HangingDisposableObject
            AddHandler Me.SayHelloEvent, AddressOf o.SayHello
            o.Dispose()
        Next

        RaiseEvent SayHelloEvent()
    End Sub

You’d be surprised.  You still get 5 Messageboxes even though all five were Disposed inside the loop.  Ah, but the garbage collector hasn’t run yet.  So let’s force it to do a collection.

    Private Sub ShowHanging()
        Dim o As HangingDisposableObject

        For i As Integer = 1 To 5
            o = New HangingDisposableObject
            AddHandler Me.SayHelloEvent, AddressOf o.SayHello
            o.Dispose()
        Next

        GC.Collect()
        RaiseEvent SayHelloEvent()
    End Sub

Still surprised?  You shouldn’t be.  The GC won’t collect (Finalize) the objects because there is still a reference to that object (the event handler).  So how do you manage this?  You have to call RemoveHandler to remove the reference.  And that means you have to keep your own references to the objects until you’re done with them and you do the cleanup yourself.

    Private Sub ShowHanging()
        Dim oCollection As New Generic.List(Of HangingObject)
        Dim o As HangingObject

        For i As Integer = 1 To 5
            o = New HangingObject
            AddHandler Me.SayHelloEvent, AddressOf o.SayHello
            oCollection.Add(o)

        Next

        RaiseEvent SayHelloEvent()

        For Each o In oCollection
            RemoveHandler Me.SayHelloEvent, AddressOf o.SayHello
        Next

    End Sub

So IDispose is not the answer.  Keeping track of your objects and the references they hold is the answer.  And that should be the obvious answer anyway.