views:

65

answers:

2

Hi,

I have a fairly simple Linq query (simplified code):

dim x = From Product In lstProductList.AsParallel 
        Order By Product.Price.GrossPrice Descending Select Product

Product is a class. Product.Price is a child class and GrossPrice is one of its properties. In order to work out the price I need to use Session("exchange_rate").

So for each item in lstProductList there's a function that does the following:

NetPrice=NetPrice * Session("exchange_rate")

(and then GrossPrice returns NetPrice+VatAmount)

No matter what I've tried I cannot access session state.

I have tried HttpContext.Current - but that returns Nothing. I've tried Implements IRequiresSessionState on the class (which helps in a similar situation in generic http handlers [.ashx]) - no luck.

I'm using simple InProc session state mode. Exchange rate has to be user specific.

What can I do?

I'm working with: web development, .Net 4, VB.net


Step-by-step:
page_load (in .aspx)
dim objSearch as new SearchClass()
dim output = objSearch.renderProductsFound()

then in objSearch.renderProductsFound:
lstProductList.Add(objProduct(1))
...
lstProductList.Add(objProduct(n))

dim x = From Product In lstProductList.AsParallel
Order By Product.Price.GrossPrice Descending Select Product

In Product.Price.GrossPrice Get :
return me.NetPrice+me.VatAmount

In Product.Price.NetPrice Get:
return NetBasePrice*Session("exchange_rate")

Again, simplified code, too much to paste in here. Works fine if I unwrap the query into For loops.

A: 

I'm not exactly sure how HttpContext.Current works, but I wouldn't be surprised if it would work only on the main thread that is processing the HTTP request. This would mean that you cannot use it on any other threads. When PLINQ executes the query, it picks some random threads from the thread pool and evaluates the predicates in the query using these threads, so this may be the reason why your query doesn't work.

If the GrossPrice property needs to access only a single thing from the session state, it should be fairly easy to change it to a method and pass the value from the session state as an argument:

Dim rate = Session("exchange_rate")
Dim x = From product In lstProductList.AsParallel  
        Order By product.Price.GetGrossPrice(rate) Descending 
        Select product 

Depending on where you use x later, you could also add a call to ToList to force the evaluation of the query (otherwise it may be executed lazily at some later time), but I think the change I described above should fix it.

Tomas Petricek
Tomas, thanks. I was thinking along the same lines in regard to parallel threads not having access to HTTPContext and using local variables, only I need to serialise this class to JSON later on - which wouldn't work with methods. The best idea I have so far is to have GrossPrice as a property and GetGrossPrice as a method - use the first for serialisation and use the latter in pLinq, there must be a more eloquent solution to this...
Dima
A: 

You should really read the values out of session state and into local variables that you know you need within the LINQ statement. Otherwise you're actually accessing the NameValueCollection instance every single time for every single element in every single thread when the value is essentially constant.

Drew Marsh
you're right, I haven't actually thought about it from this side. Since I'm using plinq is to get max performance it doesn't actually make sense to use Session inside the query.
Dima