Strange Caching issue with ASP.NET MVC using Linq - asp.net-mvc

Using asp.net MVC in c#, I am making a call to a stored procedure using Linq into my SQL Members table. I have no internal caching on the application, already checked to make sure it is turned off.
Test case:
I have my username set to test1. From the website I change my username to test2. The website still shows test1. I go to Management Studio and run my stored procedure called MemberByEmail, it shows test2 correctly.
I start simple, refresh my page to see if it's browser cache, still test1. I go to debugging and walk through the code and find that it goes correctly all the way to here to call the database:
/// <summary>Method that is mapped to the dbo.MemberByEmail database procedure.</summary>
/// <returns></returns>
[System.Data.Linq.Mapping.Function(Name="dbo.MemberByEmail")]
public System.Data.Linq.ISingleResult<BookCrossing.Data.Member> MemberByEmail(
[System.Data.Linq.Mapping.Parameter(DbType="nvarchar(100)")] string email)
{
var methodInfo = (System.Reflection.MethodInfo)System.Reflection.MethodInfo.GetCurrentMethod();
var result = this.ExecuteMethodCall(this, methodInfo, email);
return ((System.Data.Linq.ISingleResult<BookCrossing.Data.Member>)(result.ReturnValue));
}
I turned on the profiler for my sql db, and it actually shows an entry for MemberByEmail, and the result set that came back had username = test1 .
Again I ran the stored procedure through Management Studio, and it came up with test2 as the username. I waited for 15 minutes, refreshing the web page every 5 or so, and it never cleared and served the correct test2 from the db. The last strange piece, I ran IISReset and refreshed the page, test2 was returned.
I'm guessing this I am just overlooking something obvious. Any help or advice would be great. Thanks
UPDATE: I created a console application to take out the web piece of it. The problem is the same when accessing directly from a console app also, no change.

How are you calling this from the webpage? If via an Ajax call, IE helpfully caches the result for you...

Took a while but we got this resolved. Data access is done through a MemberRepository in our project, and we loaded member repository in our MembershipProvider class. The problem is that the MembershipProvider class was loaded at the start of the application and never removed, so all MemberRepository calls were done through the same context. The strange part is that the call went all the way to SQL (as noted we were able to see the request in profiler), but the bowels of the code got back the results set but instead used the first calls result set and sent that back to us.
So by moving the Repository into the desired method or our MembershipProvider, it was destroyed after each call and that solved the issue. I don't know that this is specific to our set up, but hopefully it will help someone in the future.

Related

ClaimsPrincipal.Current vs. HttpContext.Current.User?

In MVC what's the difference between these 2?
They look identical, and they even return the same Type/Class System.Web.Security.RolePrincipal but there're subtleties.
Eg. The following code throws various errors when called against the instance generated via ClaimsPrincipal.Current
cp.FindFirst(ClaimTypes.Name); //{"Unable to connect to SQL Server database."} <--HUH!?
cp.Claims; //{"Value cannot be null.\r\nParameter name: username"}
The above works when cp is this instead:
var cp = System.Web.HttpContext.Current.User
When drilling down to the private members via quick watch I can see that they both has the same Claim dictionary. However for whatever reason the public property blows when called against the object returned by ClaimsPrincipal.Current
Help - why is this!? This is driving me crazy.
=============EDIT==================
It must be almost time to go to bed.
IPrincipal supports multiple identities. It requires some kind of store.
IIdentity returns an instance of ClaimsIdentity and does not require the store.
I was simply drilling the wrong properties. The two of them are almost identical in their shape ie. same properties and methods, that I got them confused.
The Identity is the current authenticated user and the principal is the security context that the code is running under.
This article is a good explanation that I found useful http://msdn.microsoft.com/en-us/library/ftx85f8x.aspx .

A circular reference was detected while serializing with Json.Encode

I have situation where Json.Encode is working locally (localhost) which is 64bit iis7 windows 7 box.
If I deploy to windows 2003 32 bit IIS6 I get circular reference errors. Shown below 'Error here' is the line where the error starts.
#*var model = '#Html.Raw(Json.Encode(Model))';*# <<<<Error here
var model = '#Html.GetJson(Model)';
As part of trying to resolve this I thought maybe one of the project dll's that were being used on the server was different than that locally so i copied any reference dll to the server bin directory. This did not help.
I do have a fix which is pretty easy. I would have preferred to be able to identity the issue. My guess is that it is using some dll on the server differently than locally to return json via Json.Encode then on the server.
My resolution as shown 2nd line above is to use Json.Net and a mvc helper
public static MvcHtmlString GetJson(this HtmlHelper htmlHelper, ViewModel vm)
{
string s = JsonConvert.SerializeObject(vm);
return new MvcHtmlString(s);
}
Has anyone seen this and resolved? (without json.net)
Assuming you're using Entity Framework, taking a look at the entities developed by the framework will shed some light on the topic. For example, I had table called Sessions and one called Enrollments, the Enrollments table having an FK relationship to the Sessions table PK. This resulted in the Session objects having a collection of Enrollments, and the Enrollment objects having a virtual instance of the Session that the enrollment was for ... which in turn pointed to a collection of Enrollments etc ... you get the picture, AND why the circular reference issue was detected by the json serialization.
The solution was to NOT query a collection of Session objects in the code, but to query an anonymous (untyped) object with all the same fields in it instead. The prevents the Json.Encode() from getting confused about, since it doesn't know about, the circular reference that Entity Framework is OK with in the code behind / server side code.

New project fails using WebAPI and Breeze

I receive the following error when trying to run the new project per the instruction in the Readme file.
1: querying Todos
2: Query failed: The action 'Todos' on controller 'BreezeSample' with return type 'System.Collections.Generic.List`1[[MyTasks.Api.Models.BreezeSampleTodoItem, MyTasks.Api, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' cannot support querying. Ensure the type of the returned content is IEnumerable, IQueryable, or a generic form of either interface.
UPDATE:
I checked my event viewer, and see a SQL error that I've never seen before when trying to debug on my machine -
Login failed for user 'my-machine\user-name'. Reason: Failed to open the explicitly specified database. [CLIENT: ]
It seems that the database being generated by BreezeSamplesContext is inaccessible for some reason? It has been generated by code-first, but I can't query it (apparently).
UPDATE 2:
I've changed the default method to -
[HttpGet]
public IQueryable<BreezeSampleTodoItem> Todos()
{
System.Data.Entity.DbSet<BreezeSampleTodoItem> result = null;
try
{
result = _contextProvider.Context.Todos;
}
catch (Exception exc)
{
throw new Exception(exc.Message);
}
return result;
}
Although the Seed method works, and the database is dropped and repopulated with seed values, I get a response of 0 items in the 'result' above.
UPDATE: December 15
The critical piece of information ... the reason for the problem ... is the use of the pre-release SPA template.
That template is not the same as the MVC 4 Web API or Empty templates that are described in the Breeze documentation
The SPA Template and the MVC update include the beginnings of ASP.NET Web API support for OData queries. Their stab at OData conflicts with Breeze; the two forces are wrestling for ownership of the OData query. Wish we could use theirs but it is missing essential features such as support for $select and $expand.
Fortunately, it is easy to disable the MS version so that Breeze prevails. Open App_Start/WebApiConfig.cs file and delete or comment out the following:
config.EnableQuerySupport(); // conflicts with Breeze's ODataActionFilter
The misleading error about "return type" should disappear and you should be back in business.
Note that taking this step turns off the MS Web API OData filter for the entire site. We have it on our backlog to update the Breeze ODataActionFilterAttribute so that it disables the MS Web API OData handling for the Breeze controller only. We hadn't bothered yet because the SPA template remains unofficial at this time. For the nonce ... you can't mix Breeze and Web API OData queries in the same site ... unless you're prepared to do the per-controller filter cleanup yourself.
We have a Breeze version of the new SPA Template working and almost ready to release. I'll be writing about it shortly and will update this answer with a link.
Below is my previous answer which I preserve mostly because (a) it describes how to diagnose a problem and (b) is the context for the comment chain.
Let's start over and see if we can diagnose. Close all Visual Studio sessions (that should stop IIS Express). Launch a fresh VS session. Create an MVC4 Web Api application in VS 2012. Add the Breeze.MVC4WebApiClientSample NuGet package. Run it (F5). Still having trouble?
If so, let's update the controller method with a new line like this:
[HttpGet]
public IQueryable Todos() {
var items = _contextProvider.Context.Todos.ToList(); // test the query
return _contextProvider.Context.Todos;
}
Put a breakpoint on the var items ... line and re-run with the debugger (F5). Step into that line. Did it throw (not good but interesting)? If not, how many items did you get? Zero? You should have 6.
If you can't get past this point, I don't think this is a Breeze problem. Breeze hasn't done anything yet. I'd be looking for something unexpected in your environment.
Let us know how it stands when you get to this point; if still stuck we'll be ready for next steps.
The sample from NuGet is set up to drop and re-create the database every time you run the code. Do you happen to have the database open in a SQL Management Studio? I ran into this as well.
Take a look at the BreezeSampleDatabaseInitializer class. Check out the comment that talks about preserving the changes between server sessions. If you change the class to implement the DropCreateDatabaseIfModelChanges interface it will only try to drop the database when you change the model.

ASP.NET MVC4 WebApi parameter is null - on only one machine

I have MVC4 WebApi project that is working fine on my development machine but is acting
strangely on a deployed server. Both boxes are Server 2008 with IIS 7.5
I have a single controller with a single Post method that takes a complex type as
a parameter. I am forcibly using the XmlMediaType formatter and XmlSerialization so
HttpConfiguration.Formatters.XmlFormatter.UseXmlSerializer = true and the complex type is "old school" XmlSerializable.
For the same request my dev box correctly deserializes the XML in the body into
an instance of the complex type and the result returned to the client from the Post method is correct. On the other machine the parameter instance is null on arrival in the Post method.
I have to reiterate that this is identical code and an identical request (except
for host name). That makes me think there has to be something environmentally
different between the machines. Unfortunately after much searching I still have no idea what that might be.
I should also point out that if I modify my Post method to take a string parameter
and then do the deserialization myself internally the behavior on both boxes is the same and correct.
I have also implemented a custom serializer (XmlFormatter.SetSerializer) and again
the dev box works; the other produces a null parameter. Interestingly, when I log
the body of the request before deserialization in this case I see the same XML on both machines. It's just that one box drops the deserialzed value somewhere on the way to the Post method.
Can anyone offer some suggestions on how to proceed to troubleshoot this strange
behavior?
Check the ModelState on the controller. If deserialization fails for any reason, it gets recorded as a ModelState exception. It might help you at least figure out what's going on.

Entity Framework doesn't update data value changes made from database

I didn't know quite how to word this. I have an ASP.NET MVC 3 web application with a pretty standard EF 4.1 code first with existing database (non-auto-generated) repository pattern. There's a context which is under a dataservice the web app talks to.
The problem I have is this: say I have a database table with an integer column. The value is 10. If I go into the database itself and enter 25 into the table, no matter how many times I hit refresh on the browser, close the browser and reopen it, clear the browser history, etc, it still persists the value of 10. I have to republish the site.
Why does it do this? Am I blaming the right thing here? Is this an EF problem? an ASP.NET problem? Server problem? ... I don't know where to look into this.
Yes, I've struck this problem in my own applications.
The "entities" (object instances) tracked by Entity Framework are cached in memory, and aren't updated when you requery the database, in case overwriting them would clobber any changes you've made to the cached version.
You can get around it by forcing EF to overwrite existing values, but be aware that this will overwrite anything you've changed, so only do it if you know you've saved any pending changes first.
I've written this extension method to do the job:
public static class DbSetExtensions
{
public static System.Data.Objects.ObjectSet<T> Uncached<T>(this IObjectContextAdapter context)
where T : class
{
var set = context.ObjectContext.CreateObjectSet<T>();
set.MergeOption = System.Data.Objects.MergeOption.OverwriteChanges;
return set;
}
}
So using that, I can say:
var orders = myDbContext.Uncached<Order>().Where(...);
... and the orders set will contain orders that are fresh from the database, overwriting the properties of any Order objects previously queried.

Resources