Using Shared Properties in ASP.NET and WinForms

A good business library should be able to drive behavior on any number of devices, exposing a application programming interface that is agnostic of its implementation.

However, we recently had a problem when we wanted to re-use a business library that was designed for a Windows Forms application for use in an ASP.NET web application. The problem was that our original application used shared properties to manage the state of the application.

Note: it seems prudent to avoid global variables, but this was where we found ourselves.

Why was this a problem? The original design meant that each instance of the application was owned by a single user under a single process. However, in ASP.NET, all users share a single process hosted by the ASP.NET runtime. Since shared variables are unique to the process they live on, variables that managed state for a single user (i.e. ActiveClient) would now be shared, overwritten, and cleared all at once by every single user within the web application.

Without massive re-writing of the business and application logic, we needed a way to give windows app users their own global variables as well as giving web app users a way to access their own instance of the shared properties.

Here’s how we did it:

First, consider what a normal shared property would look like in VB.NET:

Private Shared _activeClient As Client
Public Shared Property ActiveClient() As Client
    Get
        Return _activeClient
    End Get
    Set(ByVal value As Client)
        _activeClient = Value
    End Set
End Property

Note: For this example, I have a class named Client but this could be any variable that I wanted to share access to across the entire application for a single user.

It’s important to breakdown all the things that a property does here. The property doesn’t actually hold the value across all instances; the private shared field does. The property just provides global accessors and setters to retrieve and set the value.

ASP.NET Session Variables

In ASP.NET, we can store values unique to each user inside of the Session Variable. To figure out how to integrate this with the first case, let’s consider what a typical session variable looks like:

'setter
Session("ActiveClient") = new Client()
'getter
Dim myClient = DirectCast(Session("ActiveClient"), Client)

This works well enough, but it’s a little messy. We have to manually perform casting ourselves and also keep track of all the key strings across the entire application.

Here’s one way to improve this (and other projects) by adding strong typing to the ASP.NET session variable:

Public Shared Property ActiveClient() As Client
    Get
        If HttpContext.Current.Session("ActiveClient") Is Nothing Then
            HttpContext.Current.Session("ActiveClient") = New Client
        End If
        Return DirectCast(HttpContext.Current.Session("ActiveClient"), Client)
    End Get
    Set(value As Client)
        HttpContext.Current.Session("ActiveClient") = value
    End Set
End Property

We still have global accessors and setters provided by the shared property, but inside of the Get and Set operations we’re using the session variable to store the value for each individual user. Note that we’re using the static HttpContext.Current Property so the code doesn’t not have to live on a page with it’s own HttpContext.

Merging Both Properties

We now have a property in a windows application that stores a value unique to each user / process and a property in a web application that stores a value unique to each user / session. All that is left to do is to merge the properties accordingly.

The first step in doing so is to determine whether or not the assembly is currently executing as a web or windows application. We can do so by checking if the HttpContext Current property exists:

Dim isWebDeployed as Boolean = System.Web.HttpContext.Current IsNot Nothing

Using that information, we can just expand the logic in our getters and setters to first check the execution environment and then grab the appropriate value:

Private Shared _activeClient As New Client
Public Shared Property ActiveClient() As Client
    Get
        'check if deployed as web application
        If System.Web.HttpContext.Current IsNot Nothing Then
            'if we've never loaded, create new instance just for session
            If System.Web.HttpContext.Current.Session("ActiveClient") Is Nothing Then
                System.Web.HttpContext.Current.Session("ActiveClient") = New Client
            End If
            Return DirectCast(System.Web.HttpContext.Current.Session("ActiveClient"), Client)
        Else
            'application is windows application
            Return _activeClient
        End If
    End Get
    Set(ByVal value As Client)
        'check if deployed as web application
        If System.Web.HttpContext.Current IsNot Nothing Then
            System.Web.HttpContext.Current.Session("ActiveClient") = Value
        Else
            _activeClient = Value
        End If
    End Set
End Property

Extended Solution

Based off the number of instances you’re dealing with, the previous solution might work just fine. However, if you need to repeat this across multiple shared properties, you might want something a little more reusable.

Here’s a generic getter method that takes in the shared private field for a windows application and the key string for a web application and returns the appropriate value:

Public Shared Function GetPropertyBasedOnEnvironment(Of T)(ByRef sharedMember As T, ByVal propName As String) As T
    'check if deployed as web application
    If HttpContext.Current IsNot Nothing Then
        'application is web application
        Return TryCast(HttpContext.Current.Session(propName), T)
    Else
        'application is windows application
        Return sharedMember
    End If
End Function

Conversely, here’s generic setter method that can access the old value and assign it a new value depending on the current environment:

Public Shared Sub SetPropertyBasedOnEnvironment(Of T)(ByRef sharedMember As T, ByVal propName As String, newValue As T)
    'check if deployed as web application
    If HttpContext.Current IsNot Nothing Then
        'application is web application
        HttpContext.Current.Session(propName) = newValue
    Else
        'application is windows application
        sharedMember = newValue
    End If
End Sub

With those two methods accessible, we can now simplify our shared property using the following code:

Private Shared _activeClient As New Client
Public Shared Property ActiveClient() As Client
    Get
        Return GetPropertyBasedOnEnvironment(_activeClient, "ActiveClient")
    End Get
    Set(value As Client)
        SetPropertyBasedOnEnvironment(_activeClient, "ActiveClient", value)
    End Set
End Property

Bonus: if you’re using .NET 4.5 or above, you can further simplify the custom getter and setter methods by using CallerMemberNameAttribute to have the compiler pass the key string for you, like this:

Public Shared Function GetPropertyBasedOnEnvironment(Of T)(
                  ByRef sharedMember As T, 
                  <CallerMemberName> Optional propName As String = Nothing) As T
    'check if deployed as web application
    If HttpContext.Current IsNot Nothing Then
        Return DirectCast(HttpContext.Current.Session(propName), T)
    Else
        Return sharedMember
    End If
End Function

Again, there might be more elegant architectural solutions, but this helped resolve the issue we were having based on the situation we had coded ourselves into.

17 comments:

  1. I am very enjoyed for this blog. Its an informative topic. It help me very much to solve some problems. Its opportunity are so fantastic and working style so speedy. villa for rent in el gouna

    ReplyDelete
  2. You can likewise ask your realtor to give you your territory and the neighboring region's predominant property costs. Different variables like the property size, condition and so forth, should likewise be thought of while evaluating the property. Homes for sale in Huntington Hills

    ReplyDelete
  3. I will likewise bring in sure that the cash experiences the books to urge some Aussie sucker to purchase properties. Lyford Cay Real Estate

    ReplyDelete
  4. Contingent upon these situations, the final product of what the model will ascertain might be altogether different. Stump Removal Stockton

    ReplyDelete
  5. At last, our post deal balance is essentially our completion balance for every year or zero in the event that we have effectively sold the property (=IF(B19=0,0,B25)). This line will make it simple for us to address our obligation when we go to build our monetary record later on. nova city rawalpindi

    ReplyDelete
  6. They can, whenever contracted for, eliminate the entirety of the appendages, and trunk areas. modern tree service tools

    ReplyDelete
  7. Trees have consistently furnished people with incalculable advantages. In the first place, trees are charitable creatures. Improve tree health Franklin

    ReplyDelete
  8. These are only a portion of the things that never occurs in Australia. Here in Australia, we serve individuals to live in is lower part of the reach, Americans can't be served thusly. park view city housing scheme islamabad

    ReplyDelete
  9. Very neat article post. Really looking forward to read more. Will read on...
    Austin tree removal team

    ReplyDelete
  10. Making it more dependable and secure for your site's information where you can set up your own security encryptions, have your own space, your own specific manner with your sites for simply a small amount of the expense of committed worker facilitating. https://onohosting.com/

    ReplyDelete
  11. This is very modest when you consider that you'd either need to convey them yourself (you could likely just convey a couple hundred every day) or need to pay a commission to a realtor.west hollywood condos for sale

    ReplyDelete
  12. Tajarat strives to be Pakistan's biggest real estate developer ever, guaranteeing the highest international standards, prompt execution, and lifetime customer loyalty. For further detail visit lahore smart city payment plan

    ReplyDelete
  13. The nearby geography and plans across the quick region will assist you with understanding the fall of the land and the effect of any inclines and regular waste. Take a gander at the area of any water courses and flood fields. Search out the historical backdrop of any flooding nearby. Nigeria real estate

    ReplyDelete
  14. Thank you ever so for you post. Keep writing.tree removal

    ReplyDelete
  15. Delta International Recruiting Agency provides highly skilled and experienced personnel for the Gulf countries as well as other areas of the world at every level in the fields in FMCG, Engineering / Construction, Information Technology, Telecommunication, Healthcare, Finance etc in addition to a broad range of the Services industry.

    ReplyDelete
  16. The close by topography and plans across the fast locale will help you with grasping the fall of the land and the impact of any slopes and customary waste. Look at the region of any water courses and flood fields. Search out the verifiable scenery of any flooding close by.. www.myindigocreditcardlogin.com

    ReplyDelete
  17. Asp DotNetSharedProperties is a crucial aspect of ASP.NET development. Concord Mw2 Hueneme It allows for sharing data across different components of a web application, enhancing efficiency and flexibility.

    ReplyDelete