Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ASP.NET MVC, Linq To SQL, and StructureMap causing DataContext to cache data

I'll start by telling my project setup:

  • ASP.NET MVC 1.0
  • StructureMap 2.6.1
  • VB

I've created a bootstrapper class shown here:

Imports StructureMap
Imports DCS.Data
Imports DCS.Services

Public Class BootStrapper

    Public Shared Sub ConfigureStructureMap()

        ObjectFactory.Initialize(AddressOf StructureMapRegistry)

    End Sub

    Private Shared Sub StructureMapRegistry(ByVal x As IInitializationExpression)

        x.AddRegistry(New MainRegistry())
        x.AddRegistry(New DataRegistry())
        x.AddRegistry(New ServiceRegistry())
        x.Scan(AddressOf StructureMapScanner)

    End Sub

    Private Shared Sub StructureMapScanner(ByVal scanner As StructureMap.Graph.IAssemblyScanner)

        scanner.Assembly("DCS")
        scanner.Assembly("DCS.Data")
        scanner.Assembly("DCS.Services")
        scanner.WithDefaultConventions()

    End Sub

End Class

I've created a controller factory shown here:

Imports System.Web.Mvc
Imports StructureMap

Public Class StructureMapControllerFactory
    Inherits DefaultControllerFactory

    Protected Overrides Function GetControllerInstance(ByVal controllerType As System.Type) As System.Web.Mvc.IController

        Return ObjectFactory.GetInstance(controllerType)

    End Function

End Class

I've modified the Global.asax.vb as shown here:

...
    Sub Application_Start()

        RegisterRoutes(RouteTable.Routes)

        'StructureMap
        BootStrapper.ConfigureStructureMap()
        ControllerBuilder.Current.SetControllerFactory(New StructureMapControllerFactory())

    End Sub
...

I've added a Structure Map registry file to each of my three projects: DCS, DCS.Data, and DCS.Services. Here is the DCS.Data registry:

Imports StructureMap.Configuration.DSL

Public Class DataRegistry
    Inherits Registry

    Public Sub New()

        'Data Connections.
        [For](Of DCSDataContext)() _
            .HybridHttpOrThreadLocalScoped _
            .Use(New DCSDataContext())

        'Repositories.
        [For](Of IShiftRepository)() _
            .Use(Of ShiftRepository)()

        [For](Of IMachineRepository)() _
            .Use(Of MachineRepository)()

        [For](Of IShiftSummaryRepository)() _
            .Use(Of ShiftSummaryRepository)()

        [For](Of IOperatorRepository)() _
            .Use(Of OperatorRepository)()

        [For](Of IShiftSummaryJobRepository)() _
            .Use(Of ShiftSummaryJobRepository)()

    End Sub

End Class

Everything works great as far as loading the dependecies, but I'm having problems with the DCSDataContext class that was genereated by Linq2SQL Classes.

I have a form that posts to a details page (/Summary/Details), which loads in some data from SQL. I then have a button that opens a dialog box in JQuery, which populates the dialog from a request to (/Operator/Modify). On the dialog box, the form has a combo box and an OK button that lets the user change the operator's name. Upon clicking OK, the form is posted to (/Operator/Modify) and sent through the service and repository layers of my program and updates the record in the database. Then, the RedirectToAction is called to send the user back to the details page (/Summary/Details) where there is a call to pull the data from SQL again, updating the details view.

Everything works great, except the details view does not show the new operator that was selected. I can step through the code and see the DCSDataContext class being accessed to update the operator (which does actually change the database record), but when the DCSDataContext is accessed to reload the details objects, it pulls in the old value. I'm guessing that StructureMap is causing not only the DCSDataContext class but also the data to be cached?

I have also tried adding the following to the Global.asax, but it just ends up crashing the program telling me the DCSDataContext has been disposed...

Private Sub MvcApplication_EndRequest(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.EndRequest

   StructureMap.ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()

End Sub

Can someone please help?

like image 606
Dragn1821 Avatar asked Mar 25 '10 18:03

Dragn1821


1 Answers

Got this response back from Jeremy Miller on the StructureMap google group:

Easy money, you're creating an instance of your DataContext object -yourself- in the registration, which de facto makes that a singleton throughout the StructureMap ecosystem.

This code:

'Data Connections. 
[For](Of DCSDataContext)() _ 
    .HybridHttpOrThreadLocalScoped _ 
    .Use(New DCSDataContext()) 

Needs to define the DataContext using -deferred- execution rather than using the pre-built "New DCSDataContext()"

If you were in C# (because I don't know the VB syntax), you would do:

For<DCSDataContext>().HybridHttpOrThreadLocalScoped().Use(() => new DCSDataContext()); 

I ran this through a C# to VB converter and it gave me this:

[For](Of DCSDataContext)() _
    .HybridHttpOrThreadLocalScoped _
    .Use(Function() New DCSDataContext())

Which works great!

like image 172
Dragn1821 Avatar answered Sep 25 '22 15:09

Dragn1821