Linq to SharePoint throwing null reference exception - linq

In our SharePoint 2010 project we are using Linq to SharePoint to get a list of ConfigurationItems. On our testing environments we never had issues fetching data from this list. On our production environment we are now sometimes (we cannot find a pattern right now) getting a null reference exception when looping through the items in the list.
Below is the exception whe are getting thrown from the Linq to SharePoint code:
Object reference not set to an instance of an object. StackTrace:
at Microsoft.SharePoint.Linq.FieldRef.GetHashCode()
at Microsoft.SharePoint.Linq.FieldRef.FieldRefEqualityComparer.GetHashCode(FieldRef obj)
at System.Linq.Set`1.InternalGetHashCode(TElement value) at System.Linq.Set`1.Find(TElement value, Boolean add) at System.Linq.Enumerable.d__7a`1.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) at Microsoft.SharePoint.Linq.SelectMappingInfo.GetDistinctMappedFields()
at Microsoft.SharePoint.Linq.Rules.PushDownProcessor.SelectWithInfoOp.PushDownSelect(Context ctx)
at Microsoft.SharePoint.Linq.Rules.PushDownProcessor.SelectWithInfoOp.Process(Context ctx)
at Microsoft.SharePoint.Linq.Rules.GuardedRule`4.c__DisplayClass7.b__6(TSourceBase src, TContext ctx)
at Microsoft.SharePoint.Linq.Rules.RewriteRule`2.Apply(TNode src, TContext ctx) at Microsoft.SharePoint.Linq.Rules.CacheRule`3.Apply(TSource src, TContext ctx)
at Microsoft.SharePoint.Linq.Rules.PushDownProcessor.b__0(Expression e, Context ctx)
at Microsoft.SharePoint.Linq.Rules.ChildRule`2.Apply(TNode src, TContext ctx) at Microsoft.SharePoint.Linq.Rules.PushDownProcessor.b__3(Expression e, Context ctx)
at Microsoft.SharePoint.Linq.Rules.RewriteRule`2.Apply(TNode src, TContext ctx) at Microsoft.SharePoint.Linq.Rules.CacheRule`3.Apply(TSource src, TContext ctx)
at Microsoft.SharePoint.Linq.SPLinqProvider.Rewrite(Expression expression, List`1& assumptions)
at Microsoft.SharePoint.Linq.SPLinqProvider.RewriteAndCompile[T](Expression expression, List`1& assumptions)
at Microsoft.SharePoint.Linq.LinqQuery`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Common.Configuration.ConfigurationRepository.GetConfiguration(String siteUrl) InnerException:
Source: Microsoft.SharePoint.Linq TargetSite: Int32 GetHashCode()
And here the code we use in our GetConfiguration method.
using (SpDataContext dataContext = new SpDataContext(siteUrl))
{
result = new ConfigurationModel()
{
Configurations = (from item in dataContext.GasportConfiguration
select new ConfigurationItem()
{
Key = item.Key,
Value = item.Value,
Environment = (Environment)Enum.Parse(typeof(Environment), item.Environment.ToString(), true)
}).ToList()
};
}
Anyone having ideas on how to track this down to what's causing this exception?
UPDATE 31-05-2011:
We found a pattern in which way we can reproduce this behaviour on our production environment. And also on our test environment we had this issue too, from which we extracted some Crash Dump files by using AdPlus.
We see this behaviour occuring after the application pool is recycled. The only way to fix this error is to perform a full IISreset.
In the crashdump analysis I found an exception message that states:
Exception Code: 0xC0000005
Exception Information: The thread tries to read from or write to a virtual address for which it does not have the appropriate access.
Hope that someone could give me some more information on this exception?

Unfortunately we haven't found a solution for this issue and decided to move away from LINQ to SharePoint. For a few lists we have changed it to SQL tables (Linq to SQL) and for the SharePoint Lists we moved back to CAML.

In our project we use Linq to Sharepoint heavily and were having this problem come up intermittently, and only on production. The only thing that seemed to work when it happened was an IISReset.
We dug into the problem a little deeper and still don't know what causes it to happen. But we found that you can automatically fix it when it occurs by clearing some private cache variables. Here's our code:
public static class SharePointless
{
public static void Reset()
{
var assembly = Assembly.GetAssembly(typeof(EntityList<>));
var providerType = assembly.GetType("Microsoft.SharePoint.Linq.SPLinqProvider");
var singleton = providerType.GetField("Singleton", BindingFlags.Static | BindingFlags.Public);
if (singleton == null) throw new Exception("Expected field doesn't exist in SPLinqProvider");
singleton.SetValue(null, Activator.CreateInstance(providerType));
var itemMappingInfoType = assembly.GetType("Microsoft.SharePoint.Linq.SPItemMappingInfo");
var cachedMappings = itemMappingInfoType.GetField("cachedMappings", BindingFlags.Static | BindingFlags.NonPublic);
if (cachedMappings == null) throw new Exception("Expected field doesn't exist in SPItemMappingInfo");
cachedMappings.SetValue(null, null);
}
}
Example usage:
public static void MyMethod(bool retry)
{
try
{
using (var db = new MyDataContext())
{
DoStuff(db);
}
}
catch (NullReferenceException ex)
{
if (retry && ex.StackTrace.Contains("FieldRef.GetHashCode"))
{
SharePointless.Reset();
MyMethod(false);
}
}
}
In our case we also had the catch code send us an email so we knew that the problem happened and the fix worked.

We came across the same thing. The following steps solved it:
Regeneration of the dataContext class via SPMetal on the server causing the problem
Reapply the class to your project and rebuild
Redeploy the solution (copying the DLL to the GAC worked)

Related

visual studio web test error handling

I'm using Visual Studio Ultimate 2013 and have a load test that uses a web test with a number of request and web test plugins.
In my PostRequest plugin, I'm checking the http status code of the response and am flagging an error in a WebTest.Context parameter, when a hhtp code of over 400 is returned. What I want to do is pick this up in the PostTransaction WebTest plugin and update a database table. The problem is, that the test aborts when the framework detects the error and the PostTransaction plugin isn't called.
I've added a PostWebTest plugin, that I thought would be called when the test iteration aborted, but it's never hitting this when a request fails. It does hit it if the test is successful. What am I missing?
public override void PostRequest(object sender, PostRequestEventArgs e)
{
...
statusCode = e.Response.StatusCode.GetHashCode();
If (statusCode > 400)
{
e.WebTest.Context["TransactionFailCount"] = 1;
}
}
public override void PostTransaction(object sender, PostTransactionEventArgs e)
{
int transactionFailCount = Convert.ToInt32(e.WebTest.Context["TransactionFailCount"]);
if (transactionFailCount > 0)
failCount = 1;
else
passCount = 1;
...
base.PostTransaction(sender, e);
}
public override void PostWebTest(object sender, PostWebTestEventArgs e)
{
base.PostWebTest(sender, e);
}
Thanks
A Web Performance Test (WPT) will continue to execute after an error is detected unless the Stop on error property of the test is true. It is possible that some aspects of a the handling of a request are not performed after an error, but I have not seen any such cases.
Be careful of terminology. WPTs use "transactions" as a way of grouping several requests. The context (right click) menu of a request has an "Add transaction" entry that selects a range of items in the test to be included in that transaction. Perhaps you should be using the PostRequest or PostPage plugins rather than PostTransaction.
I recommend that you do some experiments with a simple two or three request WPT plus some simple plugins that just announce that they have been called. For example
public override void PostRequest(object sender, PostRequestEventArgs e)
{
e.WebTest.AddCommentToResult("PostRequest called for url " + e.Request.Url);
}
Additionally, there is a good explanation of how and when plugins are called in pages 32 to 44 of the Visual Studio Performance Testing Quick Reference Guide from Codeplex.
The statement statusCode = e.Response.StatusCode.GetHashCode(); is strange. The value of e.Response.StatusCode is an enum, it integer value can be obtained by casting. The GetHashCode method is not intended to get the numeric value of an enum. The statement would be better as statusCode = (int)e.Response.StatusCode; or the assign and test (note that if is used for conditionals in C#, not If) might be better as
statusCode = e.Response.StatusCode;
if ( e.Response.StatusCode >= System.Net.HttpStatusCode.BadRequest ) { ... }

Getting DataContext error while saving form

I get this error when opening one specific form. The rest is working fine and I have no clue why this one isn't.
Error: An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
I get the error at _oDBConnection when I try to save. When I watch _oDBConnection while running through the code, it does not exist. Even when I open the main-window it does not exist. So this form is where the DataContext is built for the very first time.
Every class inherits from clsBase where the DataContext is built.
My collegue is the professional one who built it all. I am just expanding and using it (learned it by doing it). But now I'm stuck and he is on holiday. So keep it simple :-)
What can it be?
clsPermanency
namespace Reservation
{
class clsPermanency : clsBase
{
private tblPermanency _oPermanency;
public tblPermanency PermanencyData
{
get { return _oPermanency; }
set { _oPermanency = value; }
}
public clsPermanency()
: base()
{
_oPermanency = new tblPermanency();
}
public clsPermanency(int iID)
: this()
{
_oPermanency = (from oPermanencyData in _oDBConnection.tblPermanencies
where oPermanencyData.ID == iID
select oPermanencyData).First();
if (_oPermanency == null)
throw new Exception("Permanentie niet gevonden");
}
public void save()
{
if (_oPermanency.ID == 0)
{
_oDBConnection.tblPermanencies.InsertOnSubmit(_oPermanency);
}
_oDBConnection.SubmitChanges();
}
}
}
clsBase
public class clsBase
{
protected DBReservationDataContext _oDBConnection;
protected int _iID;
public int ID
{
get { return _iID; }
}
public DBReservationDataContext DBConnection
{
get { return _oDBConnection; }
}
public clsBase()
{
_oDBConnection = new DBReservationDataContext();
}
}
Not a direct answer, but this is really bad design, sorry.
Issues:
One context instance per class instance. Pretty incredible. How are you going to manage units of work and transactions? And what about memory consumption and performance?
Indirection: every entity instance (prefixed o) is wrapped in a cls class. What a hassle to make classes cooperate, if necessary, or to access their properties.
DRY: far from it. Does each clsBase derivative have the same methods as clsPermanency?
Constructors: you always have to call the base constructor. The constructor with int iID always causes a redundant new object to be created, which will certainly be a noticeable performance hit when dealing with larger numbers. A minor change in constructor logic may cause the sequence of constructor invocations to change. (Nested and inherited constructors are always tricky).
Exception handling: you need a try-catch everywhere where classes are created. (BTW: First() will throw its own exception if the record is not there).
Finally, not a real issue, but class and variable name prefixes are sooo 19xx.
What to do?
I don't think you can change your colleague's design in his absence. But I'd really talk to him about it in due time. Just study some linq-to-sql examples out there to pick up some regular patterns.
The exception indicates that somewhere between fetching the _oPermanency instance (in the Id-d constructor) and saving it a new _oDBConnection is created. The code as shown does not reveal how this could happen, but I assume there is more code than this. When you debug and check GetHashCode() of _oDBConnection instances you should be able to find where it happens.

Adding profile values for auto-generated user

I'm creating a ASP.NET MVC 3.0 website, and have a couple of different database initializations based on whether the site is intended for development, testing, or production. I'm stuck on the testing initialization, as I'm trying to get a test user created. I can get the user to create just fine, however when I try to add some profile values, I get: System.Web.HttpException: Request is not available in this context. Is there a way to add Profile values in a situation where the request isn't going to be available?
Following code is what is being run:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
if (ApplicationServices.GetInitialCatalog() != "tasktracker")
{
Database.SetInitializer(new TaskTrackerDropCreateDatabaseIfModelChanges());
}
else
{
Database.SetInitializer(new TaskTrackerCreateDatabaseIfNotExists());
}
using (var db = new TaskTrackerContext())
{
db.Database.Initialize(false);
}
}
public class TaskTrackerDropCreateDatabaseIfModelChanges : DropCreateDatabaseIfModelChanges<TaskTrackerContext>
{
protected override void Seed(TaskTrackerContext context)
{
// Set up the membership, roles, and profile systems.
ApplicationServices.InstallServices(SqlFeatures.Membership | SqlFeatures.Profile | SqlFeatures.RoleManager);
// Create the default accounts and roles.
if (ApplicationServices.GetInitialCatalog() == "tasktracker_testing")
{
if (Membership.GetUser("testuser", false) == null)
{
Membership.CreateUser("testuser", "password", "testuser#test.com");
MembershipUser user = Membership.GetUser("testuser", false);
user.IsApproved = true;
var profile = ProfileBase.Create("testuser");
profile.SetPropertyValue("FirstName", "test");
profile.SetPropertyValue("LastName", "user");
profile.SetPropertyValue("TimeZone", "US Mountain Standard Time");
profile.Save();
}
}
}
}
Interesting question. Have you looked at using the new Universal Providers? Dunno if you will run into the same httpcontext issue but may be worth a look: http://www.hanselman.com/blog/IntroducingSystemWebProvidersASPNETUniversalProvidersForSessionMembershipRolesAndUserProfileOnSQLCompactAndSQLAzure.aspx
Did you try to do a call of "Initialize()" :
profile.Initialize(username, true)
after your create action to see if the context should be Initialized.
By using Reflector i saw the ProfileBase of Initialize (see below) creates this kind of context from the settings:
public void Initialize(string username, bool isAuthenticated)
{
if (username != null)
{
this._UserName = username.Trim();
}
else
{
this._UserName = username;
}
SettingsContext context = new SettingsContext();
context.Add("UserName", this._UserName);
context.Add("IsAuthenticated", isAuthenticated);
this._IsAuthenticated = isAuthenticated;
base.Initialize(context, s_Properties, ProfileManager.Providers);
}
It seems working here, the SettingsContext() seems taking account of my custom properties declared in the web.config.
Regards,
I come back again because the solution I added with the "Initialize()" function in fact not run really after an other test. So in fact I found a way which runs correctly.
The problem of "request is not available in this context" in application_start in your case could be due to the application mode "Integrated" which is new from II7 instead of the Classic mode.
To see a good explain you ca go on the Mike Volodarsky's blog IIS7 Integrated mode: Request is not available in this context exception in Application_Start .
I copy/paste an extract which could indicate the main reason:
" *This error is due to a design change in the IIS7 Integrated pipeline that makes the request context unavailable in Application_Start event. When using the Classic mode (the only mode when running on previous versions of IIS), the request context used to be available, even though the Application_Start event has always been intended as a global and request-agnostic event in the application lifetime. Despite this, because ASP.NET applications were always started by the first request to the app, it used to be possible to get to the request context through the static HttpContext.Current field.* "
To solve this you can use a workaround that moves your first-request initialization from Application_Start to BeginRequest and performs the request-specific initialization on the first request.
A good example of code is done in his blog :
void Application_BeginRequest(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpContext context = app.Context;
// Attempt to peform first request initialization
FirstRequestInitialization.Initialize(context);
}
class FirstRequestInitialization
{
private static bool s_InitializedAlready = false;
private static Object s_lock = new Object();
// Initialize only on the first request
public static void Initialize(HttpContext context)
{
if (s_InitializedAlready)
{
return;
}
lock (s_lock)
{
if (s_InitializedAlready)
{
return;
}
// Perform first-request initialization here
//
// You can use your create profile code here....
//---
s_InitializedAlready = true;
}
}
}

CA2202 Warning from Code Analysis for OracleConnection disposal

We are getting the following warning from Code Analysis in Visual Studio 2010 and I'm wondering if this is a false positive that we can safely ignore or the code should be refactored to correctly dispose the object.
The relevant code:
public void MyFunction()
{
OracleConnection oraConnection = null;
OracleCommand oraCommand = null;
try
{
// Connect to the database
oraConnection = new OracleConnection(connectionString);
oraConnection.Open();
// Prepare and run the query
oraCommand = new OracleCommand(sqlQuery, oraConnection);
oraCommand.ExecuteNonQuery();
}
catch { throw; }
finally
{
// Perform a safe cleanup
if (oraCommand != null) { oraCommand.Dispose(); }
if (oraConnection != null)
{
oraConnection.Close();
oraConnection.Dispose();
}
}
}
The relevant error message:
Warning 18 CA2202 : Microsoft.Usage : Object 'oraConnection' can be disposed
more than once in method 'ClassName.MyFunction()'. To avoid generating a
System.ObjectDisposedException you should not call Dispose more than one
time on an object.
If you remove the line:
oraConnection.Close();
it should get rid of the warning, since closing and disposing a connection are essentially the same thing.
You might also want to replace your try/finally by a using statement.
Note that Microsoft's own guidelines say that IDisposable.Dispose should be implemented in such a way that it can safely be called multiple times. Which means that the CA2202 warning can safely be ignored, as noted in the comment by JoeM27 on the MSDN page for CA2202.

Visual Studio: Who is writing to console?

OK, here's a good one (I think) - I'm working on an application with lots (far too many) dependency dlls, created by a team of developers. I'm trying to debug just one assembly, but the console output is 'polluted' by the Console.WriteLines and Debug.WriteLines left scattered around the code.
Is there anyway I can work out exactly which assembly a given line is coming from, so I can get the author to clean up their source?
UPDATE If you're also experiencing this kind of issue, note that there is another potential source of output messages which is any breakpoints with 'When hit' set to print a message. Having said which, this is a VERY cool feature, which can prevent the kind of problems I was having above.
Yes - replace Console.Out. Use Console.SetOut after creating a TextWriter which not only dumps the requested data to the original console, but also dumps a stack trace (and timestamp, and the requested data) to a file.
Here's some code, adapted from Benjol's answer:
(Note: you will want to adapt this code depending on whether you want a stack trace after each write, or after each writeline. In the code below, each char is followed by a stack trace!)
using System.Diagnostics;
using System.IO;
using System.Text;
public sealed class StackTracingWriter : TextWriter
{
private readonly TextWriter writer;
public StackTracingWriter (string path)
{
writer = new StreamWriter(path) { AutoFlush = true };
}
public override System.Text.Encoding Encoding
{
get { return Encoding.UTF8; }
}
public override void Write(string value)
{
string trace = (new StackTrace(true)).ToString();
writer.Write(value + " - " + trace);
}
public override void Write(char[] buffer, int index, int count)
{
Write(new string(buffer, index, count));
}
public override void Write(char value)
{
// Note that this will create a stack trace for each character!
Write(value.ToString());
}
public override void WriteLine()
{
// This is almost always going to be called in conjunction with
// real text, so don't bother writing a stack trace
writer.WriteLine();
}
protected override void Dispose(bool disposing)
{
writer.Dispose();
}
}
To use this for logging both Console.WriteLine and Debug.WriteLine to a file, make calls like this as early as possible in your code:
var writer = new StackTracingWriter(#"C:\Temp\ConsoleOut.txt");
Console.SetOut(writer);
Debug.Listeners.Add(new TextWriterTraceListener(writer));
Note that this currently doesn't also write to the original console. To do so, you'd need to have a second TextWriter (for the original console) in StackTracingWriter, and write to both places each time. Debug will however continue to be written to the original console.
Download Reflector and you can open up the mscorlib assembly, add your application's assemblies, then right click on the Console class and click Analyze and you can show all methods that reference the Console class.

Resources