Best asp.net-mvc questions in August 2010

asp.net mvc3 razor documentation?

16 votes

Is there any documentation on how to use Razor view engine using asp.net mvc3? or any other resources?

Trying to find it in google and msdn with no luck so far.

I would think that there will be no official documentation on MSDN as yet due to the status of the Razor and MVC3. However check

  1. http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx
  2. Introducing “Razor” – a new view engine for ASP.NET
  3. ASP.NET MVC 3: New @model keyword in Razor
  4. ASP.NET MVC 3: Layouts with Razor
  5. ASP.NET MVC 3: Server-Side Comments with Razor
  6. ASP.NET MVC 3: Razor’s @: and syntax
  7. ASP.NET MVC 3: Implicit and Explicit code nuggets with Razor
  8. ASP.NET MVC 3: Layouts and Sections with Razor
  9. Razor Syntax Quick Reference - Phil Haack
  10. Introduction to ASP.NET Web Programming Using the Razor Syntax
  11. ASP.NET MVC 3 and the @helper syntax within Razor

Haacked also has a post as well, and provides link to other resources including ,Brad Wilson, Scott Gu and others.

New: http://www.asp.net/learn/whitepapers/mvc3-release-notes

Unit testing with EF4 "Code First" and Repository

13 votes

I am attempting to get a handle on Unit testing a very simple ASP.NET MVC test app I've built using the Code First approach in the latest EF4 CTP. I'm not very experience with Unit testing / mocking etc.

This is my Repository class:

public class WeightTrackerRepository
{
    public WeightTrackerRepository()
    {
        _context = new WeightTrackerContext();
    }

    public WeightTrackerRepository(IWeightTrackerContext context)
    {
        _context = context;
    }

    IWeightTrackerContext _context;

    public List<WeightEntry> GetAllWeightEntries()
    {
        return _context.WeightEntries.ToList();
    }

    public WeightEntry AddWeightEntry(WeightEntry entry)
    {
        _context.WeightEntries.Add(entry);
        _context.SaveChanges();
        return entry;
    }
}

This is IWeightTrackerContext

public interface IWeightTrackerContext
{
    DbSet<WeightEntry> WeightEntries { get; set; }
    int SaveChanges();
}

...and its implementation, WeightTrackerContext

public class WeightTrackerContext : DbContext, IWeightTrackerContext
{
    public DbSet<WeightEntry> WeightEntries { get; set; }
}

In my test, I have the following:

[TestMethod]
public void Get_All_Weight_Entries_Returns_All_Weight_Entries()
{
    // Arrange
    WeightTrackerRepository repos = new WeightTrackerRepository(new MockWeightTrackerContext());

    // Act
    List<WeightEntry> entries = repos.GetAllWeightEntries();

    // Assert
    Assert.AreEqual(5, entries.Count);
}

And my MockWeightTrackerContext:

class MockWeightTrackerContext : IWeightTrackerContext
{
    public MockWeightTrackerContext()
    {
        WeightEntries = new DbSet<WeightEntry>();
        WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("01/06/2010"), Id = 1, WeightInGrams = 11200 });
        WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("08/06/2010"), Id = 2, WeightInGrams = 11150 });
        WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("15/06/2010"), Id = 3, WeightInGrams = 11120 });
        WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("22/06/2010"), Id = 4, WeightInGrams = 11100 });
        WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("29/06/2010"), Id = 5, WeightInGrams = 11080 });
    }

    public DbSet<WeightEntry> WeightEntries { get;set; }

    public int SaveChanges()
    {
        throw new NotImplementedException();
    }
}

My problem occurs when I'm trying to build up some test data as I can't create a DbSet<> as it has no constructor. I get the feeling I'm barking up the wrong tree with my whole approach trying to mock my context. Any advice would be most welcome to this complete unit testing newbie.

You create a DbSet through the Factory method Set() on the Context but you don't want any dependency on EF in your unit test. Therefore, what you need to look at doing is implementing a stub of DbSet using the IDbSet interface or a Stub using one of the Mocking frameworks such as Moq or RhinoMock. Assuming you wrote your own Stub you'd just add the WeightEntry objects to an internal hashset.

You may have more luck learning about unit testing EF if you search for ObjectSet and IObjectSet. These are the counterparts to DbSet prior to the code first CTP release and have a lot more written about them from a unit testing perspective.

Here's an excellent article on MSDN that discusses testability of EF code. It uses IObjectSet but I think it's still relevant.

As a response to David's comment I'm adding this addendum below as it wouldn't fit in the -comments. Not sure if this is the best practice for long comment responses?

You should change the IWeightTrackerContext interface to return an IDbSet from the WeightEntries property rather than a DbSet concrete type. You can then create a MockContext either with a mocking framework (recommended) or your own custom stub. This would return a StubDbSet from the WeightEntries property.

Now you will also have code (i.e Custom Repositories) that depend on the IWeightTrackerContext which in production you would pass in your Entity Framework WeightTrackerContext that would implement IWeightTrackerContext. This tends to be done through constructor injection using an IoC framework such as Unity. For testing the repository code that depends on EF you would pass in your MockContext implementation so the code under test thinks it's talking to the "real" EF and database and behaves (hopefully) as expected. As you have removed the dependancy on the changeable external db system and EF you can then reliably verify repository calls in your unit tests.

A big part of the mocking frameworks is providing the ability to verify calls on Mock objects to test behaviour. In your example above your test is actually only testing the DbSet Add functionality which shouldn't be your concern as MS will have unit tests for that. What you'd want to know is that the call to the Add on DbSet was made from within your own repository code if appropriate and that is where the Mock frameworks come in.

Sorry I know this is a lot to digest but if you have a read through that article a lot will become clearer as Scott Allen is a lot better at explaining this stuff than I am :)

Razor/CSHTML - Any Benefit over what we have?

11 votes

Anyone out there using the new CSHTML pages feature and is finding that they prefer this new view engine syntax over the existing ASP.NET MVC default view engine or over web forms, and if so, why? What about CSHTML gives you an advantage over MVC or web forms, or vice versa?

Just curious to hear people's take on it.

Thanks.

One of the benefits is that Razor views can be rendered inside unit tests, this is something that was not easily possible with the previous ASP.Net renderer.

From ScottGu's announcement this is listed as one of the design goals:

Unit Testable: The new view engine implementation will support the ability to unit test views (without requiring a controller or web-server, and can be hosted in any unit test project – no special app-domain required).

Is Razor view with ASPX .Master page possible?

11 votes

Is it possible to keep my existing .master page and have it used with a new ASP.NET MVC 3 Razor view? I tried this:

@{
   LayoutPage = "~/Views/Shared/Site.master";
 }

And it gives me this error message:

The file '~/Views/Shared/Site.master' could not be rendered, because it does not exist or is not a valid page.

Unfortunately no. Master pages are a part of the ASPX WebForms view engine, not the MVC framework so Razor cannot interoperate with it.

One option would be to duplicate the masters, as you mentioned, but rather than copying all the code, you could factor the Master page into a bunch of ASPX partials that the Razor and ASPX masters could embed. Then you can start converting each page and partial, one-by-one, to Razor and eventually get rid of the ASPX master.

What is the elegant solution for unrelated views in MVC web frameworks?

10 votes

I've had a problem with the following issue in Rails and ASP.Net MVC. Often there are multiple widgets of functionality on a page, yet one controller action is supposed to render the page. Let me illustrate:

Let's say I have a normal e-commerce site, and the menu is made of categories, while the page is to display an group of products.

For the products, let's say I have an action on a controller that looks something like:

def product_list
     @products = Products.find_by_category(:name => 'lawnmowers')
end

And I have a layout with something like

<div id="menu"><%= render :partial => 'menu' %></div>
<div id="content"><%= yield %></div>

The products have a view...

<%= render :partial => 'product', :collection => @products %>

(note I've ommited the product view as irrelevant)

And the menu has a partial...

<% Category.each {|c| %>
   <%= render :partial => 'menu_node', :locals => { :category => c } %>
<% } %>

The line I have a problem with is the "Category.each.do" in the view. I'm fetching data in the view, as opposed to using variables that were set and bound in the controller. And it could easily be a more complex method call that produces the menu.

The solutions I've considered are:

-A view model base class that knows how to get various pieces of data. But you could end up with one of these for each conceptual "section" of the site.
-a local variable that populates at the top of each method (violates DRY) -the same thing, but in a before_filter call

None of these seem very elegant to me. I can't help but look at this problem and think that a MVP presenter per view (not screen) is a more elegant solution.

ASP.Net MVC has render action (different from rails render :action), which does address this, but I'm not sure what I think of that solution.

Thoughts? Solution suggestions?

Added Note: The answers provided so far are good suggestions. And they apply to the example I gave, where a menu is likely present in every layout, and is clearly secondary to the product data.

However, what if there is clearly no second class citizen? Portal type sites commonly have multiple unrelated widgets, in which each is important.

For example, What if this page was displaying weather trends, with widgets for temperature, humidity, and precipitation (and each is a different model and view type).

In rails we like to have a concept of thin-controllers, thick-models. So I think you're right to not want to have variables set in the controller.

Also, in order to enable a more-complex method later on, I recommend doing something like:

/app/controllers/application_controller.rb

before_filter :add_menu_nodes

def add_menu_nodes
  @menu_nodes = Category.menu_nodes(current_user)
end

/app/views/layouts/application.html.erb

<%= render :partial=>:menu, :locals=>{:categories=>@menu_nodes} %>

/app/models/category.rb

def self.menu_nodes(current_user)
  Category.all.order(:name)
end

That way in the future you could update Category.menu_nodes with a more complicated solution, based on the current user, if you need.

What's the point of Html.DisplayTextFor()?

9 votes

Is there a good reason to use the strongly typed html helper...

<%: Html.DisplayTextFor(model => model.Email) %>

As opposed to...

<%: Model.Email %> 

Consider the following Model:

public class MyModel
{
    public string Name { get; set; }

    [DisplayFormat(NullDisplayText = "No value available!")]
    public string Email { get; set; }

}

in my view:

<%= Html.DisplayTextFor(m => m.Email) %>

<%: Model.Email %>

The first line will display "No value available" if we leave the Email to be 'null' whereas the second line will not display anything.

Conclusion: Html.DisplayTextFor will take into consideration the DataAnnotations on your properties, <%: Model.Email %> will not. Also <%: Model.Email %> will throw an "Object reference error" when the value is null, but <%= Html.DisplayTextFor %> wont.

Displaying friendly, localized enum values using DataAnnotations in ASP.NET MVC2

8 votes

What's the recommended way to display localized enum properties in MVC2?

If I have a model like this:

public class MyModel {
  public MyEnum MyEnumValue { get; set; } 
}

and a line in the view like this:

<%: Html.DisplayFor(model => model.MyEnumValue) %>

I was hoping to just annotate the enum values with DisplayAttribute like this:

public enum MyEnum
{
    [Display(Name="EnumValue1_Name", ResourceType=typeof(Resources.MyEnumResources))]
    EnumValue1,
    [Display(Name="EnumValue2_Name", ResourceType=typeof(Resources.MyEnumResources))]
    EnumValue2,
    [Display(Name="EnumValue3_Name", ResourceType=typeof(Resources.MyEnumResources))]
    EnumValue3
}

That's not supported. It seems there's something else needed. What's the nicest way to implement it?

take a look at this question may be it is usefull!
http://stackoverflow.com/questions/3431515/in-asp-net-mvc-can-i-make-a-default-editor-template-for-enum

MVC philosophy applied to webforms.

8 votes

I'm pretty new to programming in general (really started only 2 1/2 years ago) and I'm trying to decide what the best way is to approach a web app I'm making at work. A senior developer at work is encouraging me to get into MVC and after a good 24 hours of pouring over blogs, source code and other material on the subject I'm beginning to understand why I'd want to use it.

At the same time though, our company's existing apps are written as WebForms so I don't want to do something as drastic as using the actual ASP.NET MVC framework to make my app(would it really be THAT drastic though?).

What I'd really like to know is whether or not it would be practical or even possible to do WebForms but still follow the MVC philosophy of separation of concerns. Will I really just be adding an unnecessary layer to an already complicated .aspx + codebehind page?

Everyone in the blogosphere seems to think that they MUST use some kind of framework if they want to do MVC. What in WebForms is stopping them from just doing it themselves?

If a senior in your team is encouraging you to look into MVC for your app and you think it's a good move then go for it (if this app is stand-alone especially).

You can also look into the MVVM pattern. This is what many have done with WebForms and it is very similar to the MVC pattern. By applying the MVVM pattern to WebForms you would be showing how one can still use WebForms but get much of the goodness that is in the MVC pattern with ASP.Net MVC. It would be a nice way to show other devs in the team what can be done to make WebForms more SOC and testable without abandoning WebForms outright.

Here's a few more links on MVVM:

http://weblogs.asp.net/craigshoemaker/archive/2009/11/03/vm-workshop-model-view-viewmodel-mvvm-and-the-presentation-model-pattern-in-5-ui-platforms.aspx

http://russelleast.wordpress.com/2008/08/09/overview-of-the-modelview-viewmodel-mvvm-pattern-and-data-binding/

MVVM is also very popular in Silverlight apps....

There is also the MVP pattern as well. Here's an open source implementation for WebForms. This particular implementation is used by DotNetNuke 5.3.

A bit more explanation from MS on MVP and .Net

Either one of these is a great choice if you want to gain more control of your code but still have the WebForms features you enjoy and/or want to continue to have for any reason such as what it sounds like in your case of a lot of legacy code using it.

Why is there no intellisense in ASP.Net MVC 2.0 when assigning Model values to JavaScript?

8 votes

I'm trying to add some Model properties into my JavaScript within my content page:

$(document).ready(function () {
    createPager(1, <%=Model.TotalPages %>);
    createUnprocessedPager(1, <%=Model.TotalUnprocessedPages %>);
});

Does anyone know if this is by design? Are you not meant to combine Model properties with JavaScript? Or is this a bug?

This works as expected. However, I do not have any Intellisense within the <% ... %> tags when actually writing the code. If I write any code within <script> tags, then there's no Intellisense. If I go directly under the tag </script> and type <% Model.... %> then boom, I have Intellisense again.

UPDATE: 22/10/2010

Just read Scott Guthrie's latest blog post and it appears this functionality is coming out soon with the up coming release of ASP.Net MVC 3 (possibly for the beta as well):

Note: Visual Studio Code/Markup Intellisense and Colorization within Razor files aren’t enabled yet with the Beta earlier this month. You’ll see this show up in a few weeks though – and it will support full code intellisense for HTML, JavaScript, CSS and C#/VB code within Razor files.

You will loose you Intellisense in the views inside quotes "" like attributes.

<input type="text" value="<%= DateTime.Today.ToShortDateString() %>" />

or if it appears inside of Javascript blocks.

<script type="text/javascript">
    <%= DateTime.Today.ToShortDateString() %>
    </script>

It is my opinion that there should be Intellisense in these scenarios, so I would say it is a bug and hope future updates to Visual Studio will address and resolve this.

What does mean ":" in <%: and what is the difference to <%= ?

8 votes

In ASP.NET MVC 2 <%: tag was introduced to replace <%= for Html helpers. But what does it mean and what is the difference to the previous one? When shall I use <%= and when <%:?

Thank you

In ASP.NET 4 the <%: xyz %> syntax will do the same thing as <%= Server.HtmlEncode(xyz) %> did in previous versions. It is simply a shortcut because it is used so often.

As Richard says below, it can also determine if a string does not need to be encoded based on whether or not it implements the IHtmlString interface.

When is it right to use ViewData instead of ViewModels?

7 votes

Assuming you wanted to develop your Controllers so that you use a ViewModel to contain data for the Views you render, should all data be contained within the ViewModel? What conditions would it be ok to bypass the ViewModel?

The reason I ask is I'm in a position where some of the code is using ViewData and some is using the ViewModel. I want to distribute a set of guidelines in the team on when it's right to use the ViewData, and when it's just taking shortcuts. I would like opinions from other developers who have dealt with this so that I know my guidelines aren't just me being biased.

Just to further Fabian's comment; you can explicitly ensure viewdata is never used by following the steps outlined in this article. There's really no excuse not to use models for everything.

If you have no choice but to use ViewData (say on an existing project); at the very least use string constants to resolve the names to avoid using 'magic strings'. Something along the lines of: ViewData[ViewDataKeys.MyKey] = myvalue; Infact, I use this for just about anything that needs to be "string-based" (Session Keys, Cache Keys, VaryByCustom output cache keys, etc).

Are there any action filters in your project you feel are a must-have?

7 votes

I'm still not totally clear on why I would need to build custom action filters. Maybe a couple examples would help.

Are there any action filters in your project that you feel are a must-have? Maybe even so important that you re-use them across all your MVC projects?

I use a "Logging" Action Filter to log all calls to my controllers with a dump of the parameters - this can be very useful during third-party testing allowing me to see how/why/when people are interacting with the application.

Although not an Action Filter, I also place a logging hook into my repositories that dumps the SQL generated by any Linq2SQL code ... again useful to see exactly what is being executed and when.

Can automapper map a foreign key to an object using a repository?

7 votes

I'm trying out Entity Framework Code first CTP4. Suppose I have:

public class  Parent
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Child
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Parent Mother { get; set; }
}

public class TestContext : DbContext
{
    public DbSet<Parent> Parents { get; set; }
    public DbSet<Child> Children { get; set; }
}

public class ChildEdit
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int MotherId { get; set; }
}

Mapper.CreateMap<Child, ChildEdit>();

Mapping to the Edit model is not a problem. On my screen I select the mother through some control (dropdownlist, autocompleter, etc) and the Id of the mother gets posted in back:

[HttpPost]
public ActionResult Edit(ChildEdit posted)
{
    var repo = new TestContext();

    var mapped = Mapper.Map<ChildEdit, Child>(posted);  // <------- ???????
}

How should I solve the last mapping? I don't want to put Mother_Id in the Child object. For now I use this solution, but I hope it can be solved in Automapper.

        Mapper.CreateMap<ChildEdit, Child>()
            .ForMember(i => i.Mother, opt => opt.Ignore());

        var mapped = Mapper.Map<ChildEdit, Child>(posted);
        mapped.Mother = repo.Parents.Find(posted.MotherId);

EDIT This works, but now I have to do that for each foreign key (BTW: context would be injected in final solution):

        Mapper.CreateMap<ChildEdit, Child>();
            .ForMember(i => i.Mother,
                       opt => opt.MapFrom(o => 
                              new TestContext().Parents.Find(o.MotherId)
                                         )
                      );

What I'd really like would be:

        Mapper.CreateMap<int, Parent>()
            .ForMember(i => i, 
                       opt => opt.MapFrom(o => new TestContext().Parents.Find(o))
                      );

        Mapper.CreateMap<ChildEdit, Child>();

Is that possible with Automapper?

First, I'll assume that you have a repository interface like IRepository<T>

Afterwards create the following class:

public class EntityConverter<T> : ITypeConverter<int, T>
{
    private readonly IRepository<T> _repository;
    public EntityConverter(IRepository<T> repository)
    {
        _repository = repository;
    }
    public T Convert(ResolutionContext context)
    {
        return _repository.Find(System.Convert.ToInt32(context.SourceValue));       
    }
}

Basically this class will be used to do all the conversion between an int and a domain entity. It uses the "Id" of the entity to load it from the Repository. The IRepository will be injected into the converter using an IoC container, but more and that later.

Let's configure the AutoMapper mapping using:

Mapper.CreateMap<int, Mother>().ConvertUsing<EntityConverter<Mother>>();

I suggest creating this "generic" mapping instead so that if you have other references to "Mother" on other classes they're mapped automatically without extra-effort.

Regarding the Dependency Injection for the IRepository, if you're using Castle Windsor, the AutoMapper configuration should also have:

IWindsorContainer container = CreateContainer();
Mapper.Initialize(map => map.ConstructServicesUsing(container.Resolve));

I've used this approach and it works quite well.

Domain Object in Views

7 votes

We've been having a discussion at work about whether to use Domain Objects in our views (asp.net mvc 2) or should every view that requires data be sent a ViewModel?

I was wondering if anyone had any pros/cons on this subject that they could shed some light on?

Thank you

I like to segregate my Domain Objects from my Views. As far as I'm concerned, my Domain Objects are solely for the purpose of representing the Domain of the application, now how the application is displayed.

The presentation layer should not contain any domain logic. Everything they display should be pre-determined by their Controller. The ideal way to ensure this is always adhered to is to ensure the view only receives these flattened ViewModels.

I did ask a similar question myself. Here's a quote from the answer I accepted:

I think that there are merits to having a different design in the domain than in the presentation layer. So conceptually you are actually looking at two different models, one for the domain layer and one for the presentation layer. Each of the models is optimized for their purpose.

If I have the domain objects for Customer > Sales > Dispatch Address, then I don't want to have to deal with the object traversal in my view. I create a flattened view model that contains all of the properties. There's almost no extra work in mapping to and from this flattened view/presentation model if you use the excellent open source project AutoMapper.

Also, why would you want to pass an entire domain object back to a view if you can create an optimised representation of that model?

should I install asp.net mvc 2 on a deploy machine ?

6 votes

I'm deploying an asp.net mvc 2 app on windows 2008 R2 and I get error that there is no system.web.mvc.dll, Should I install mvc2 on the deploy machine ?

You can actually deploy without MVC being installed on the server by deploying the MVC DLLs with your project. Put the following DLLs into your bin directory and it will run fine

System.Web.Mvc
System.Web.Routing
System.Web.Abstractions

If your server is on .Net 3.5 SP1 then you only need to deploy the Web.Mvc DLL, if its not running SP1 then you will need to deploy all 3.

There is an article by Phil Haack here detailing this more http://haacked.com/archive/2008/11/03/bin-deploy-aspnetmvc.aspx

Proper structuring of Lucene.Net usage in an ASP.NET MVC site

6 votes

I'm building an ASP.NET MVC site where I plan to use Lucene.Net. I've envisioned a way to structure the usage of Lucene, but not sure whether my planned architecture is OK and efficient.


My Plan:

  • On Application_Start event in Global.asax: I check for the existence of the index on the file system - if it doesn't exist, I create it and fill it with documents extracted it from the database.
  • When new content is submitted: I create an IndexWriter, fill up a document, write to the index, and finally dispose of the IndexWriter. IndexWriters are not reused, as I can't imagine a good way to do that in an ASP.NET MVC application.
  • When content is edited: I repeat the same process as when new content is submitted, except that I first delete the old content and then add the edits.
  • When a user searches for content: I check HttpRuntime.Cache to see if a user has already searched for this term in the last 5 minutes - if they have, I return those results; otherwise, I create an IndexReader, build and run a query, put the results in HttpRuntime.Cache, return them to the user, and finally dispose of the IndexReader. Once again, IndexReaders aren't reused.

My Questions:

  • Is that a good structure - how can I improve it?
  • Are there any performance/efficiency problems I should be aware of?
  • Also, is not reusing the IndexReaders and IndexWriters a huge code smell?

The answer to all three of your questions is the same: reuse your readers (and possibly your writers). You can use a singleton pattern to do this (i.e. declare your reader/writer as public static). Lucene's FAQ tells you the same thing: share your readers, because the first query is reaaalllyyyy slow. Lucene handles all the locking for you, so there is really no reason why you shouldn't have a shared reader.

It's probably easiest to just keep your writer around and (using the NRT model) get the readers from that. If it's rare that you are writing to the index, or if you don't have a huge need for speed, then it's probably OK to open your writer each time instead. That is what I do.

Edit: added a code sample:

public static IndexWriter writer = new IndexWriter(myDir);

public JsonResult SearchForStuff(string query)
{
    IndexReader reader = writer.GetReader();
    IndexSearcher search = new IndexSearcher(reader);
    // do the search
}

Thread.CurrentPrincipal claims incorrectly to be anynomous

6 votes

I'm seeing requests on my server that appear to be made by an anynomous client, although I'm certain they were made by an authenticated user - I have fiddler logs showing that the client sent valid asp.net auth cookies, and server logs indicating that the cookie arrived and is valid. The problem has been observed across all browsers.

The flow of data is:

  1. User visits login url, on a machine that's part of a webfarm (all with the same machine, decrypt keys)
  2. On successful forms authentication, user is redirect to a restricted url, their homepage
  3. Homepage renders correctly, knowns the identify of the user, and includes javascript to perform 7 asynchronous post-backs to get additional data
  4. Javascript kicks off 7 http.get requests, hitting different machines in the webfarm (assume round robin)
  5. Server validates request: ~0.01% fail to authenticate.

Thoughts?

Now into details:

A very small number of the asynchronous requests land at my server (with evidence they were not manipulated or faked) and appear to be anonymous. Of the 7 requests made, some number may or may not work (ie, 5/7 will succeed, 2 will fail). There doesn't appear to be any patterns in success / failures. In the cases where my requests appear to be anonymous, the CurrentPrincipal.Identity records:

Thread.CurrentPrincipal.Identity.IsAuthenticated; // false
Thread.CurrentPrincipal.Identity.Name; // null (or empty, unsure off hand)

Dumping the http.context.request.params collection to a log file, I'm able to see the following relevent (and scrubbed) properties (complete params below):

context: {"userId":10000,"userName":"johnsmith"}
HTTP_COOKIE:.ASPXAUTH=[valid auth cookie value]
HTTP_X_REQUESTED_WITH:XMLHttpRequest
X-Requested-With: XMLHttpRequest
    AUTH_TYPE: 
    AUTH_USER: 
    AUTH_PASSWORD: 
    LOGON_USER: 
    REMOTE_USER: 
    HTTP_COOKIE: .ASPXAUTH=[valid auth cookie value]

I know the auth cookie is valid - during these same requests I'm able to decrypt the auth cookie and extract the following:

CookiePath: /
Expiration: 9/23/2105 8:14:22 PM
Expired: False
IsPersistent: True
IssueDate: 8/30/2010 2:54:22 PM
Name: johnsmith
UserData: 
Version: 2

Not sure how to proceed at this point. This problem seems to have been exacerbated with our recent migration to mvc 2.0 / asp.net 4.0, but my confidence isn't high that was the cause.

I've reached out to a handful of my customers who have had this problem, and that's been even more frustrating (but does reflect what I'm able to read in my logs). Once in this state, it's hard to get out of it. Clearing cache and cookies seem to have no effect. But, switching to a new browser and it's generally OK. Likewise, waiting several hours and returning with the same browser and it's also generally ok, but not always. As stated earlier, this is seen across all browsers.

Any suggestions?
Kevin




------------
Here is the remainder of the log snippet (scrubbed for pii) that I've captured:

8/30/2010 2:54:43 PM: Anonymous user detected:
    Identity Name:
    IsAuthenticated::False
HttpContextInformation to follow:

8/30/2010 2:54:43 PM: Request Param collection contents:
context: {"userId":10000,"userName":"johnsmith"}
    .ASPXAUTH: A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
    ASP.NET_SessionId: m5vit3cyv0rsiosqg5xmhhuu
    ALL_HTTP: HTTP_CONNECTION:close
HTTP_ACCEPT:text/javascript, text/html, application/xml, text/xml, */*
HTTP_ACCEPT_ENCODING:gzip, deflate
HTTP_ACCEPT_LANGUAGE:en-us
HTTP_COOKIE:.ASPXAUTH=A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
HTTP_HOST:www.host.com
HTTP_REFERER:http://www.host.com/
HTTP_USER_AGENT:Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
HTTP_X_FORWARDED_FOR:166.137.139.139
HTTP_X_REQUESTED_WITH:XMLHttpRequest

    ALL_RAW: Connection: close
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-us
Cookie: .ASPXAUTH=A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
Host: www.host.com
Referer: http://www.host.com/
User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
X-Forwarded-For: 166.137.139.139
X-Requested-With: XMLHttpRequest

    APPL_MD_PATH: /LM/W3SVC/792523/Root
    APPL_PHYSICAL_PATH: d:\localpath\
    AUTH_TYPE: 
    AUTH_USER: 
    AUTH_PASSWORD: 
    LOGON_USER: 
    REMOTE_USER: 
    CERT_COOKIE: 
    CERT_FLAGS: 
    CERT_ISSUER: 
    CERT_KEYSIZE: 
    CERT_SECRETKEYSIZE: 
    CERT_SERIALNUMBER: 
    CERT_SERVER_ISSUER: 
    CERT_SERVER_SUBJECT: 
    CERT_SUBJECT: 
    CONTENT_LENGTH: 0
    CONTENT_TYPE: 
    GATEWAY_INTERFACE: CGI/1.1
    HTTPS: off
    HTTPS_KEYSIZE: 
    HTTPS_SECRETKEYSIZE: 
    HTTPS_SERVER_ISSUER: 
    HTTPS_SERVER_SUBJECT: 
    INSTANCE_ID: 792523
    INSTANCE_META_PATH: /LM/W3SVC/792523
    LOCAL_ADDR: 10.248.50.207
    PATH_INFO: /resource
    PATH_TRANSLATED: d:\localpath\resource
    QUERY_STRING: context={%22userId%22:10000,%22userName%22:%22johnsmith%22}
    REMOTE_ADDR: 10.208.205.171
    REMOTE_HOST: 10.208.205.171
    REMOTE_PORT: 37966
    REQUEST_METHOD: GET
    SCRIPT_NAME: /resouce
    SERVER_NAME: www.host.com
    SERVER_PORT: 80
    SERVER_PORT_SECURE: 0
    SERVER_PROTOCOL: HTTP/1.0
    SERVER_SOFTWARE: Microsoft-IIS/6.0
    URL: /resource
    HTTP_CONNECTION: close
    HTTP_ACCEPT: text/javascript, text/html, application/xml, text/xml, */*
    HTTP_ACCEPT_ENCODING: gzip, deflate
    HTTP_ACCEPT_LANGUAGE: en-us
    HTTP_COOKIE: .ASPXAUTH=A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
    HTTP_HOST: www.host.com
    HTTP_REFERER: http://www.host.com/
    HTTP_USER_AGENT: Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
    HTTP_X_FORWARDED_FOR: 166.137.139.139
    HTTP_X_REQUESTED_WITH: XMLHttpRequest


8/30/2010 2:54:43 PM: Auth Ticket collection contents:
    CookiePath: /
    Expiration: 9/23/2105 8:14:22 PM
    Expired: False
    IsPersistent: True
    IssueDate: 8/30/2010 2:54:22 PM
    Name: johnsmith
    UserData: 
    Version: 2

This answer works, but is disappointing and alarming at the same time.

I spent 2 months working part time with MSDN technical support, and we finally found a work-around for this problem. I'm going to leave it to Microsoft to fix the problem, as it’s almost certainly an issue in the .net framework. But first, let me summarize the problem, give additional relevant background information and a few interesting things we found along the way.

The symptom was fleeting: Our website had a few reports of users who would authenticate with our website and see the correct state. But seemingly randomly, they’d be signed out of our website, or occasionally, experience the anonymous view. It was very frustrating, an nearly impossible to reproduce locally, in house.

Also on symptoms: through logging we saw mobile (iphone, ipad & android) browsers were disproportionately impacted, although all browsers and operating systems were impacted to some degree. And one last random symptom: It’d work for a user one day, not the next, and later in the afternoon, work again. Of course, switching browsers almost always fixed the problem.

We quickly assumed an auth issue, likely around the authentication cookie. The strange part was, I was able to prove (tracing) that the requests that were erroring included a proper cookie that I was able to decrypt, but that the .net framework was ignoring, in a non-deterministic way. I eventually began logging all requests that were in this state – auth cookie ignored by the .net framework, but seemingly valid to me, and found around 2% of my users were impacted.

I switched from using Thread.CurrentPrincipal.Identity to HttpContext.Current.User.Identity, to no avail, and tried a handful of other settings. Curiously, the only change I was able to make that made a dent was migrate to the .net 4 framework (from 3.5). The problem became an order of magnitude worst. Also tried various load balancer configurations, and was able to rule out multiple machine configurations – the same machine that issued the auth cookie would later reject it.

To re-iterate the symptoms: we had certain users (non-deterministic) who at times would not be able to user our website in an authenticated mode (also non-deterministic). Cute.

By now, the product team in Redmond was involved, and also stumped. But they did come up with a suggestion, which ultimately resolved the issue, here goes: Try forcing the Microsoft.net framework to use cookies as the authentication mode, as opposed to using a cookieless state:

<authentication mode="Forms">
  <forms cookieless="UseCookies" />
</authentication>

Flipped the switch and instantly the problematic requests ended (once I expired the session of those in an odd state).

While I’m glad that the problem was resolved – or rather worked around, it’s the non-deterministic handling of various browsers that worries me. Why would the .net framework see a browser one day, and treat it as supporting cookies, and later the same day say it should use a cookieless session?

My last concern is around how many other sites out there are losing 2% of their authenticated traffic without knowing? Considering the fix, it feels very much like a bug in the .net 4 framework.

jQuery.Load() not triggering Request.IsAjaxRequest in ASP.NET MVC2

5 votes

I'm using the Jquery full calendar plugin, and i want to be able to click on an event and the details of the event to be populated via AJAX into a div with the id of #details.

here is my controller action that i'm trying to load. When debugging, the action does not consider the incoming request to be AJAX and returns the full view instead of the partial. Does it matter if the full view is called the same as the partial view? Ie; 'Details.aspx' & 'Details.ascx'?

public ActionResult Details(int id)
    {
        Pol_Event pol_Event = eventRepo.GetEvent(id);
        ViewData["EventTypes"] = et.GetEventType(id);
        if (pol_Event == null)
            return View("NotFound");
        else
        {
            if(HttpContext.Request.IsAjaxRequest()){
                return PartialView("Details");
            }
            else
                return View(pol_Event);

        }
    }

Here is the jquery code i'm using. Am i missing not using .load() correctly in the eventClick function? The Developer of the calendar plugin has confirmed that eventClick has nothing to do with AJAX so the fault must lie in my code.

$(document).ready(function() {
            $('#calendar').fullCalendar({

                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'month,agendaWeek,agendaDay'
                },

                events: "/Events/CalendarData",
                allDayDefault: false,

                selectable: true,
                eventClick: function(event) {
                    $('details').load(event.url);
                },
                eventRender: function(event, element) {
                    element.qtip({
                        content: event.title + " @ " + event.venue,

                        position: {
                            corner: {
                                target: 'topLeft',
                                tooltip: 'bottomLeft'
                            }
                        }

                    });
                }


            });

        });

So am i using the Jquery.Load() function incorrectly, or is there something wrong with my controller?

More updates: I finally caught the problem. The XMLHttpRequest is being sent but i'm encountering a 500 internal server error, not solved yet as i can't figure out what's causing the error.

Host: localhost:4296
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 
Firefox/3.6.8
Accept: text/html, */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
X-Requested-With: XMLHttpRequest
Referer: http://localhost:4296/Events/EventCalendar
Cookie: .ASPXAUTH=56C5F4FD536564FF684F3F00E9FB51A5F2F1B22D566C517923D71FEAF599D266531CAC52BF49D2700E048DD420A4575456855303CC2DCB5875D4E1AD8883821EA62E5169969503776C78EB3685DAA48C

UPDATE: I finally figured out what the problem was. I wasn't passing in the model to the partial so the line

return PartialView("Details");

Should have been

return PartialView("Details", pol_Event);

this was generating the 500 internal service error.

When you make an Ajax request you're suppose to set the 'X-Requested-With' HTTP header to something like 'XMLHttpRequest' eg.

Host                www.google.com
User-Agent          Mozilla/5.0 (Windows; U; Windows NT 6.1; (snip...)
Accept              */*
Accept-Language     en-us,en;q=0.5
Accept-Encoding     gzip,deflate
Accept-Charset      ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive          115
Connection          keep-alive
X-Requested-With    XMLHttpRequest
Referer             http://www.google.com

This 'X-Requested-With' header is what the 'IsAjaxRequest()' method looks for. Normally, jQuery's Ajax methods will send this header automatically. My guess is that for some reason the jQuery Calendar plugin isn't sending this header.

I would download something like fiddler, or install Firebug for Firefox and check the raw HTTP Request/Response data when the Ajax request/Calendar control is fired/initialised. See if the X-Requested-With header is being included.