Is this code thread-safe? How can I make it thread-safe? - c#

I have a WCF service with a security class for getting some of the attributes of the calling user. However I'm quite bad when it comes to thread safety - to this point, I haven't needed to do much with it, and only have a rudimentary theoretical understanding of the problems of multi-threading.
Given the following function:
public class SecurityService
{
public static Guid GetCurrentUserID()
{
if (Thread.CurrentPrincipal is MyCustomPrincipal)
{
MyCustomIdentity identity = null;
MyCustomPrincipal principal = (MyCustomPrincipal)Thread.CurrentPrincipal;
if (principal != null)
{
identity = (MyCustomIdentity)principal.Identity;
}
if (identity != null)
{
return identity.UUID;
}
}
return Guid.Empty;
}
}
Is there any chance that something could go wrong in there if the method is being called at the same time from 2 different threads? In my nightmares I see terrible consequences if these methods go wrong, like someone accidentally getting someone else's data or suddenly becoming a system administrator. A colleague (who also he was not an expert, but he's better than me) thought it would probably be okay because there's not really any shared resources that are being accessed there.
Or this one, which will access the database - could this go awry?
public static User GetCurrentUser()
{
var uuid = GetCurrentUserID();
if (uuid != null)
{
var rUser = new UserRepository();
return rUser.GetByID(uuid);
}
return null;
}
There's a lot of discussion about the principals of threading, but I tend to fall down and get confused when it comes to actually applying it, and knowing when to apply it. Any help appreciated.
I can explain more about the context/purpose of these functions if it's not clear.
EDIT: The rUser.GetByID() function basically calls through to a repository that looks up the database using NHibernate. So I guess the database here is a "shared resource", but not really one that gets locked or modified for this operation... in which case I guess it's okay...?

From what I see, the first example only accesses thread-local storage and stack-based variables, while the second one only accesses stack-based variables.
Both should be thread-safe.
I can't tell if GetByID is thread safe or not. Look to see if it accesses any shared/static resources. If it does, it's not thread-safe without some additional code to protect those resources.

The code that you have above doesn't contain any code that changes global state, therefore you can be fairly sure that it won't be a problem being called by multiple simlutaneous threads. Security principal information is tied to each thread, so no problem there either.

Related

Use static class in ASP.NET Web API

I am posting this question using an automatic translation.
Please forgive any grammatical errors.
I have built an application using the .NET framework and the ASP.net Web API.
I have split the virtual path for each customer region within a site running on IIS and copied the same binary to run as separate applications.
The applications run in the same application pool.
Recently, some customers have been making a very large number of requests in a matter of minutes.
(I suspect a glitch in the system on the customer's end).
I am thinking of adding a static class to my current application that keeps track of the number of requests per customer in a given time period and blocks them if the threshold is exceeded.
From past StackOverFlow articles I have found that "information in the static class is lost if the application pool is recycled", but I have determined that this is not a problem in this case.
For my purposes, I only need to be able to retain information for a few minutes.
However, I still have a few questions that I can't find answers to, so I'd like to ask you all a few questions.
Even if the same binary is running in the same application pool, will the static class information be kept separately for different applications?
Will the static constructor of a static class be executed even after the application pool is recycled?
Is there a problem if I reference a field in Global.asax from within a static class?
Is there a problem with referencing the contents of web.config from within a static class?
Attached below is the source of my experimental implementation.
I plan to call the static method "ExcessiveRequestCheck.isExcessiveRequest" of this static class after the Web API receives the request and identifies the user ID.
Any advice would be sincerely appreciated.
P.S.
I understand that this approach does not work well in a load balancing environment. Currently my system only runs on one virtual machine. If you are moving to the cloud or deploying a load balancer, you will probably need a different approach than this one.
public static class ExcessiveRequestCheck
{
private static Dictionary<string, ExcessiveRequestInfo> dicExcessiveRequestCheckInfo = new Dictionary<string, ExcessiveRequestInfo>();
private static object initLock = new object();
private static object dicExcessiveRequestCheckInfoLock = new object();
//If possible, I want this process to be a static constructor
public static Dictionary<int, int> dicExcessiveRequestSkipConditions
{
get
{
lock (initLock)
{
if (ExcessiveRequestCheck._dicExcessiveRequestSkipConditions == null)
{
//if possible, I want to set this value from Web.config.
ExcessiveRequestCheck._dicExcessiveRequestSkipConditions = new Dictionary<int, int>() {
{ 5, 3 }, { 15, 5 }, { 45, 10 }, { 120, 20 }
};
}
return ExcessiveRequestCheck._dicExcessiveRequestSkipConditions;
}
}
}
private static Dictionary<int, int> _dicExcessiveRequestSkipConditions = null;
public const int BUFFER_CLEAR_MINUTES = 5;
public static bool isExcessiveRequest(string userId)
{
ExcessiveRequestCheck.refreshExcessiveRequestCheckInfo();
lock (ExcessiveRequestCheck.dicExcessiveRequestCheckInfoLock)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.ContainsKey(userId) == false)
{
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.Add(userId, new ExcessiveRequestInfo() { countRequest = 1 });
return false;
}
bool doSkip = false;
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].countRequest++;
foreach (KeyValuePair<int, int> pair in ExcessiveRequestCheck.dicExcessiveRequestSkipConditions)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].lastRequesttTime.AddSeconds(pair.Key) > DateTime.Now)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].countRequest > pair.Value)
{
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].wasRequestSkip = true;
doSkip = true;
}
}
}
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].lastRequesttTime = DateTime.Now;
return doSkip;
}
}
public static void refreshExcessiveRequestCheckInfo()
{
lock (ExcessiveRequestCheck.dicExcessiveRequestCheckInfoLock)
{
var keyList = ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.Keys;
foreach (string key in keyList)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.ContainsKey(key))
{
var value = ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[key];
if (value.lastRequesttTime.AddMinutes(BUFFER_CLEAR_MINUTES) < DateTime.Now)
{
if (value.wasRequestSkip)
{
//this NLog instance was created in Global.asax.cs
WebApiApplication.logger.Fatal("skip request! user id=" + key);
}
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.Remove(key);
}
}
}
}
}
}
class ExcessiveRequestInfo
{
public DateTime requestStartTime { get; set; } = DateTime.Now;
public DateTime lastRequesttTime { get; set; } = DateTime.Now;
public int countRequest { get; set; } = 0;
public bool wasRequestSkip { get; set; } = false;
}
Your questions
Even if the same binary is running in the same application pool, will the static class information be kept separately for different applications?
Yes, they are separate
Will the static constructor of a static class be executed even after the application pool is recycled?
Yes, the static constructor is guaranteed to be called before any of the static methods are executed
Is there a problem if I reference a field in Global.asax from within a static class?
No more than accessing it from anywhere else
Is there a problem with referencing the contents of web.config from within a static class?
No more than accessing it from anywhere else
Your general approach
DoS
If you're trying to mitigate a denial-of-service attack or credential stuffing attack, your approach probably won't work, since requests to your service will still result in load being added to your server, and if they are performing a credential stuffing attack, it'll fill up your dictionary with millions of entries and possibly cause your application to crash.
If you want to mitigate a denial-of-service attack effectively, you will probably need a more network-oriented solution, such as a smart firewall or a WAF.
Rate limiting
If on the other hand you are attempting to throttle specific users' activities (i.e. rate limiting), again, your approach probably isn't the greatest, because it does not support load balancing-- your list is held in in-process memory. For per-user rate limiting you will probably need to track user activity in a central data store accessible to all of your servers.
Static constructors
As a general rule, you should try to avoid static constructors, or keep them very simple, as a failure in a static constructor will cause your entire application to fail to start. Be careful!
even if the same binary is running in the same application pool, will the static class information be kept separately for different applications?
If by different applications, you mean separate web sites? yes, it will be kept separate to each web site you have running for that app pool.
Will the static constructor of a static class be executed even after the application pool is recycled?
Hum, that's a bit confusing. The constructor will only be executed if you call the class and that given constructor. Since there is never a instance of the class created, then the "initialize/new" event is never used nor triggered. So, any method with parameters will run and work fine - including the constructor. I would suggest that there is not some "event" that gets triggered on first use - it would not and does not make sense in the context of a static class, since you never create an instance. So, if you have some methods with parameters then fine.
So, constructor in the context of new instance of the class makes no sense - (did not even think that is possible with static).
There is no concept of "new" event that triggers, so I fail to see how this issue can ever matter.
Is there a problem if I reference a field in Global.asax from within a static class?
Well, values in that class are global to ALL users. But, those values can go out of scope just about any old time you please. As a result, ZERO use of public members is practial. While a app-pool re-start will re-set those class values? They can go out of scope just about any old time. They are global to all and every user. So, persisting values, or attempting to persit values in a static class is NOT a viable choice for production code. You can have methods (code) in that class, but any public persisting values really can't be relied upon to persist correctly. I'm not 100% sure, but even just general .net garbage collection would likely cause a re-set.
If you need this information to persist, then you can't use static, you have to create a instance of that class and persist it in session(). And session is per user.
A static class public values will apply to EVERY user - not just the current user. In effect those values are global to all users - but without any real ccontrol or garrutee that the values will persit - you have no control over this and thus you can't adopt this concpet and design for any system of practial value.
Is there a problem with referencing the contents of web.config from within a static class?
Reading values? No problem. Update or modify values? - a MASSIVE different issue. You modify web.config, that will trigger a app pool restart.
So, you free to read any file - text files, xml or whatever, and that includes web.config. As long as you not modify such files, then no problems.
The main issue here?
It simple not practical to assume, or build a design in which public static class values are to persist. The ZERO control you have when such values may go out of scope is somthing you have ZERO control over, and thus such designs can't use nor rely on values persisting.
And of course on many web hosting systems? They are now adopting cloud computing. This means from one post back to the next, you might be using a different server, and again, that means such values can't persist in memory, since from one post-back to the next, or one web service call to the next? You may well be hitting a different server anyway (and they don't share memory) (so, this suggests say using SQL server based sessions, or at the very least persisting such values in a database).
In fact, if you need such persisting values and data? Then use a database. The WHOLE idea of web based software is you do NOT have state between post-backs. And you are attempting to go even down a worse road, but hope on a wing and a prayer that some global values "might" and "sort of" and "maybe" will persist between calls to the web site.
Answer:
You really can't do this with any realm of reliably.
So, most of your questions don't really matter. What matters is these values are to persist, and you can't rely on such a design. If you need some persisting values, then you have to adopt a system and design that supports that concept (viewstate, cookies, or session()).
Now, I suppose you can give this a try, and then come back with a detailed report and how your experience turned out. But, there are too many pit falls, and without any code or system control over persisting values in memory, I don't think I would go down this road.
In web land, it makes next to no sense to have public variables that you attempt to persist in a static class. You can have code, you can have cool methods, you can use session(). But, the concept of persisting values in static class is a design choice that does not make sense, and can't be relied upon.
Web software is assumed to be state-less, and that VERY much is the assumption you have to make in regards to a static class, or in fact general use of such code.

ThreadStatic and ASP.NET

I've got a requirement to protect my business object properties via a list of separate authorization rules. I want my authorization rules to be suspended during various operations such as converting to DTOs and executing validation rules (validating property values the current user does not have authorization to see).
The approach I'm looking at wraps the calls in a scope object that uses a [ThreadStatic] property to determine whether the authorization rules should be run:
public class SuspendedAuthorizationScope : IDisposable
{
[ThreadStatic]
public static bool AuthorizationRulesAreSuspended;
public SuspendedAuthorizationScope()
{
AuthorizationRulesAreSuspended = true;
}
public void Dispose()
{
AuthorizationRulesAreSuspended = false;
}
}
Here is the IsAuthorized check (from base class):
public bool IsAuthorized(string memberName, AuthorizedAction authorizationAction)
{
if (SuspendedAuthorizationScope.AuthorizationRulesAreSuspended)
return true;
var context = new RulesContext();
_rules.OfType<IAuthorizationRule>()
.Where(r => r.PropertyName == memberName)
.Where(r => r.AuthorizedAction == authorizationAction)
.ToList().ForEach(r => r.Execute(context));
return context.HasNoErrors();
}
Here is the ValidateProperty method demonstrating usage (from the base class):
private void ValidateProperty(string propertyName, IEnumerable<IValidationRule> rules)
{
using (new SuspendedAuthorizationScope())
{
var context = new RulesContext();
rules.ToList().ForEach(rule => rule.Execute(context));
if (HasNoErrors(context))
RemoveErrorsForProperty(propertyName);
else
AddErrorsForProperty(propertyName, context.Results);
}
NotifyErrorsChanged(propertyName);
}
I've got some tests around the scoping object that show that the expected/correct value of SuspendedAuthorizationScope.AuthorizationRulesAreSuspended is used as long as a lambda resolves in the scope of the using statement.
Are there any obvious flaws to this design? Is there anything in ASP.NET that I should be concerned with as far as threading goes?
There are two concerns that I see with your proposed approach:
One's failure to use using when creating SuspendedAuthorizationScope will lead to retaining open access beyond intended scope. In other words, an easy to make mistake will cause security hole (especially thinking in terms of future-proofing your code/design when a new hire starts digging in unknown code and misses this subtle case).
Attaching this magic flag to ThreadStatic now magnifies the previous bullet by having possibility of leaving open access to another page since the thread will be used to process another request after it's done with the current page, and its authorization flag has not been previously reset. So now the scope of authorization lingering longer than it should goes not just beyond missing call to .Dispose(), but actually can leak to another request / page and of completely different user.
That said, the approaches I've seen to solving this problem did involve essentially checking the authorization and marking a magic flag that allowed bypass later on, and then resetting it.
Suggestions:
1. To at least solve the worst variant (#2 above), can you move magic cookie to be a member of your base page class, and have it an instance field that is only valid to the scope of that page and not other instances?
2. To solve all cases, is it possible to use Functors or similar means that you'd pass to authorization function, that would then upon successful authorization will launch your Functor that runs all the logic and then guarantees cleanup? See pseudo code example below:
void myBizLogicFunction()
{
DoActionThatRequiresAuthorization1();
DoActionThatRequiresAuthorization2();
DoActionThatRequiresAuthorization3();
}
void AuthorizeAndRun(string memberName, AuthorizedAction authorizationAction, Func privilegedFunction)
{
if (IsAuthorized(memberName, authorizationAction))
{
try
{
AuthorizationRulesAreSuspended = true;
privilegedFunction();
}
finally
{
AuthorizationRulesAreSuspended = true;
}
}
}
With the above, I think it can be thread static as finally is guaranteed to run, and thus authorization cannot leak beyond call to privilegedFunction. I think this would work, though could use validation and validation by others...
If you have complete control over your code and don't care about hidden dependencies due to magic static value you approach will work. Note that you putting big burden on you/whoever supports your code to make sure there is never asynchronous processing inside your using block and each usage of magic value is wrapped with proper using block.
In general it is bad idea because:
Threads and requests are not tied one-to one so you can run into cases when you thread local object is changing state of some other request. This will even more likely to happen in you use ASP.Net MVC4+ with async handlers.
static values of any kind are code smell and you should try to avoid them.
Storing request related information should be done in HttpContext.Items or maybe Session (also session will last much longer and require more careful management of cleaning up state).
My concern would be about the potential delay between the time you leave your using block and the time it takes the garbage collector to get around to disposing of your object. You may be in a false "authorized" state longer than you intend to be.

Microsoft's remark to ReaderWriterLockSlim.IsReadLockHeld/IsWriteLockHeld and its consequences

To synchronize the access to my properties I use the ReaderWriterLockSlim class. I use the following code to access my properties in a thread-safe way.
public class SomeClass
{
public readonly ReaderWriterLockSlim SyncObj = new ReaderWriterLockSlim();
public string AProperty
{
get
{
if (SyncObj.IsReadLockHeld)
return ComplexGetterMethod();
SyncObj.EnterReadLock();
try
{
return ComplexGetterMethod();
}
finally
{
SyncObj.ExitReadLock();
}
}
set
{
if (SyncObj.IsWriteLockHeld)
ComplexSetterMethod(value);
else
{
SyncObj.EnterWriteLock();
ComplexSetterMethod(value);
SyncObj.ExitWriteLock();
}
}
}
// more properties here ...
private string ComplexGetterMethod()
{
// This method is not thread-safe and reads
// multiple values, calculates stuff, ect.
}
private void ComplexSetterMethod(string newValue)
{
// This method is not thread-safe and reads
// and writes multiple values.
}
}
// =====================================
public static SomeClass AClass = new SomeClass();
public void SomeMultiThreadFunction()
{
...
// access with locking from within the setter
AClass.AProperty = "new value";
...
// locking from outside of the class to increase performance
AClass.SyncObj.EnterWriteLock();
AClass.AProperty = "new value 2";
AClass.AnotherProperty = "...";
...
AClass.SyncObj.ExitWriteLock();
...
}
To avoid unnecessary locks whenever I get or set multiple properties a once I published the ReaderWriterLockSlim-Object and lock it from outside of the class every time I'm about to get or set a bunch of properties. To achieve this my getter and setter methods check if the lock has been acquired using the IsReadLockHeld property and the IsWriteLockHeld property of ReaderWriterLockSlim. This works fine and has increased the performance of my code.
So far so good but when I re-read the documentation about IsReadLockHeld and IsWriteLockHeld I noticed the remark form Microsoft:
This property is intended for use in asserts or for other debugging
purposes. Do not use it to control the flow of program execution.
My question is: Is there a reason why I should not use IsReadLockHeld/IsWriteLockHeld for this purpose? Is there anything wrong with my code? Everything works as expected and much faster than using recursive locks (LockRecursionPolicy.SupportsRecursion).
To clarify this up: This is a minimal example. I don't want to know if the lock itself is necessary or can be removed or achieved in a different way. I just want to know why I should not use IsReadLockHeld/IsWriteLockHeld to control the flow of the programm as stated by the documentation.
After some further research I posted the same question on the German Support Forum of the Microsoft Developer Network and got into discussion with the very helpful moderator Marcel Roma. He was able to contact the programmer of the ReaderWriterLockSlim Joe Duffy who wrote this answer:
I'm afraid my answer may leave something to be desired.
The property works fine and as documented. The guidance really is just
because conditional acquisition and release of locks tends to be buggy
and error-prone in practice, particularly with exceptions thrown into
the mix.
It's typically a good idea to structure your code so that you either
use recursive acquires, or you don't, (and of course the latter is
always easier to reason about); using properties like IsReadLockHeld
lands you somewhere in the middle.
I was one of the primary designers of RWLS and I have to admit it has
way too many bells and whistles. I don't necessarily regret adding
IsReadLockHeld -- as it can come in handy for debugging and assertions
-- however as soon as we added it, Pandora's box was opened, and we RWLS was instantly opened up to this kind of usage.
I'm not surprised that people want to use it as shown in the
StackOverflow thread, and I'm sure there are some legitimate scenarios
where it works better than the alternatives. I merely advise erring on
the side of not using it.
To sum things up: You can use the IsReadLockHeld and the IsWriteLockHeld property to acquire a lock conditionally and everything will work fine, but it is bad programming style and one should avoid it. It is better to stick to recursive or non-recursive locks. To maintain a good coding style IsReadLockHeld and IsWriteLockHeld should only be used for debugging purposes.
I want to thank Marcel Roma and Joe Duffy again for their precious help.
Documentation is advising you the right thing.
Considere the following interleaved execution.
Thread1.AcqrireReadLock();
Thread1.ComplexGetterMethod();
Thread2.ReadIsReaderLockHeldProperty();
Thread1.ReleaseReadLock();
Thread2.ComplexGetterMethod(); // performing read without lock.
The other wrong thing with your code that I see is
SyncObj.EnterReadLock();
try
{
return ComplexGetterMethod();
}
finally
{
SyncObj.ExitReadLock();
}
is not the right way to do things. This is one right:
try
{
SyncObj.EnterReadLock();
return ComplexGetterMethod();
}
finally
{
if (SyncObj.IsReadLockHeld)
SyncObj.ExitReadLock();
}
And this shall be exact definition of your getter method.

Name for this pattern? (Answer: lazy initialization with double-checked locking)

Consider the following code:
public class Foo
{
private static object _lock = new object();
public void NameDoesNotMatter()
{
if( SomeDataDoesNotExist() )
{
lock(_lock)
{
if( SomeDataDoesNotExist() )
{
CreateSomeData();
}
else
{
// someone else also noticed the lack of data. We
// both contended for the lock. The other guy won
// and created the data, so we no longer need to.
// But once he got out of the lock, we got in.
// There's nothing left to do.
}
}
}
}
private bool SomeDataDoesNotExist()
{
// Note - this method must be thread-safe.
throw new NotImplementedException();
}
private bool CreateSomeData()
{
// Note - This shouldn't need to be thread-safe
throw new NotImplementedException();
}
}
First, there are some assumptions I need to state:
There is a good reason I couldn't just do this once an app startup. Maybe the data wasn't available yet, etc.
Foo may be instantiated and used concurrently from two or more threads. I want one of them to end up creating some data (but not both of them) then I'll allow both to access that same data (ignore thread safety of accessing the data)
The cost to SomeDataDoesNotExist() is not huge.
Now, this doesn't necessarily have to be confined to some data creation situation, but this was an example I could think of.
The part that I'm especially interested in identifying as a pattern is the check -> lock -> check. I've had to explain this pattern to developers on a few occasions who didn't get the algorithm at first glance but could then appreciate it.
Anyway, other people must do similarly. Is this a standardized pattern? What's it called?
Though I can see how you might think this looks like double-checked locking, what it actually looks like is dangerously broken and incorrect double-checked locking. Without an actual implementation of SomeDataDoesNotExist and CreateSomeData to critique we have no guarantee whatsoever that this thing is actually threadsafe on every processor.
For an example of an analysis of how double-checked locking can go wrong, check out this broken and incorrect version of double-checked locking:
C# manual lock/unlock
My advice: don't use any low-lock technique without a compelling reason and a code review from an expert on the memory model; you'll probably get it wrong. Most people do.
In particular, don't use double-checked locking unless you can describe exactly what memory access reorderings the processors can do on your behalf and provide a convincing argument that your solution is correct given any possible memory access reordering. The moment you step away even slightly from a known-to-be-correct implementation, you need to start the analysis over from scratch. You can't assume that just because one implementation of double-checked locking is correct, that they all are; almost none of them are correct.
Lazy initialization with double-checked locking?
The part that I'm especially interested in identifying as a pattern is the check -> lock -> check.
That is called double-checked locking.
Beware that in older Java versions (before Java 5) it is not safe because of how Java's memory model was defined. In Java 5 and newer changes were made to the specification of Java's memory model so that it is now safe.
The only name that comes to mind for this kind of is "Faulting". This name is used in iOS Core-Data framework to similar effect.
Basically, your method NameDoesNotMatter is a fault, and whenever someone invokes it, it results in the object to get populated or initialized.
See http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFaultingUniquing.html for more details on how this design pattern is used.

DbLinq - Cache problem

I'm using linq to sql for MySql (using DbLinq) in an ASP.NET MVC website. I have a weird caching problem. Consider the following methods in my Repository class:
public IEnumerable<Message> GetInbox(int userId)
{
using(MyDataContext repo = new MyDataContext(new MySqlConnection("[Connectionstring]")))
{
return repo.Messages.Where(m => m.MessageTo == userId);
}
}
public IEnumerable<Message> GetOutbox(int userId)
{
using (MyDataContext repo = new MyDataContext(new MySqlConnection("[Connectionstring]")))
{
return repo.Messages.Where(m => m.MessageFrom == userId);
}
}
'MyDataContext' is the by DbLinq generated mapping to my database, which inherits from DataContext. I'm not reusing the datacontext here (the above code looks a bit silly but I wanted to make absolutely sure that it was not some datacontext / mysqlconnection re-using issue).
What happens is, whichever of the two methods I call, with whatever userId, the results stay the same. Period. Even though I can see that repo.Messages has more than 10 results, with varying MessageFrom and MessageTo values, I only get the first-queried results back. So if I call GetInbox(4374) it gives me message A and message B. Calling GetInbox(526) afterwards still gives me message A and B, even though there are messages C and D who do have a userId of 526. I have to restart the application to see any changes.
What's going on here? I'm sure I'm doing something so stupid that I'm going to be ashamed when someone points it out to me. If I'm not doing something very stupid, then I find this issue very strange. I read about not reusing DataContext, but I am not. Why this caching issue? Below is my controller code, but I doubt it matters:
[Authorize]
public ActionResult Inbox(int userId)
{
Mailbox inbox = new Mailbox(userId, this.messageRepository.GetInbox(userId));
return PartialView("Inbox", inbox);
}
Though there are similar questions on SO, I haven't found an answer to this exact question. Many thanks!
UPDATE:
changing the code to: return repo.Messages.ToList().Where(m => m.MessageFrom == userId); fixes it, it works fine then. Seems like some cache problem. However, I of course don't want to fix it that way.
Changing the code so that the datacontext is not disposed after the query does not fix the problem.
I wrote some pretty similar code that seems to work fine. The only difference is that as Marc suggests, I'm passing in the connection string and calling ToList on the Where method. My Database is not automatically generated but derives from DataContext. The code is below.
class Program
{
static void Main(string[] args)
{
List<Item> first = GetItems("F891778E-9C87-4620-8AC6-737F6482CECB").ToList();
List<Item> second = GetItems("7CA18DD1-E23B-41AA-871B-8DEF6228F96C").ToList();
Console.WriteLine(first.Count);
Console.WriteLine(second.Count);
Console.Read();
}
static IEnumerable<Item> GetItems(string vendorId)
{
using (Database repo = new Database(#"connection_string_here"))
{
return repo.GetTable<Item>().Where(i => i.VendorId.ToString() == vendorId).ToList(); ;
}
}
}
Start of by writing a test. This will tell you wether Linq2Sql is behaving correctly. Something like:
var inboxMessages = this.messageRepository.GetInbox(userId1);
Assert.That(inboxMessages.All(m => m.MessageTo == userId1);
inboxMessages = this.messageRepository.GetInbox(userid2);
Assert.That(inboxMessages.All(m => m.MessageTo = userid2);
If that succeeds, you should really check wether it's the deferred execution that's causing problems. You should enumerate inboxMessages right away.
Another thing that might be causing trouble, is the fact that you start enumerating when the datacontext is already disposed. The only way to solve this, is not to dispose it at all (and rely on the GC cleaning it up when it goes out of scope), or come up with a custom IDisposable object, so you can put a using around it. Something like:
using(var inboxMessages = this.messageRepository.GetInbox(userId1))
{
Assert.That(inboxMessages.All(m => m.MessageTo == userId1);
}
Caching in LINQ-to-SQL is associated with the DataContext, and is mainly limited to identity caching - in most cases it will re-run a query even if you've done it before. There are a few examples, like .Single(x=>x.Id == id) (which has special handling).
Since you are clearly getting a new data-context each time, I don't think that is the culprit. However, I'm also slightly surprised that the code works... are you sure that is representative?
LINQ's Where method is deferred - meaning it isn't executed until you iterate the data (for example with foreach). But by that time you have already disposed the data-context! Have you snipped something from the example?
Also - by giving it a SqlConnection (that you don't then Dispose()), you may be impacting the cleanup - it may be preferable to just give it (the data-context) the connection string.
Well, it seemed that it was a problem with DbLinq. I used source code from 3 weeks old and there was an apparant bug in QueryCache (though it has always been in there). There's a complete thread that covers this here.
I updated the dblinq source. Querycache is now disabled (does imply a performance hit) and well at least now it works. I'll have to see if the performance is acceptable. Must confess that I'm a bit baffled though as what I'm trying to do is a common linq2sql pattern. Thanks all.
I'd avoid using DBLinq for production code... many of Linq-To-SQL's features aren't implemented, and walking through the source code shows a low level of maturity... many of the methods are not implemented or marked as "unterminated".
...you've been warned!

Categories

Resources