I'm using Visual Studio 2013 Update 2 and I'm getting an unhandled exception in one of my controllers and I can't figure where it's coming from. This is the controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Data.Entity;
using Microsoft.AspNet.Identity;
namespace SophicCeramics.Controllers
{
public class ShopController : BaseController
{
public ActionResult Cart()
{
var order = FindOrCreateOrder();
var m = new Models.Order.Cart(); //
m.Date = order.OrderDate;
m.Total = order.OrderLineItems.Sum(i => i.Quantity * i.UnitPrice);
m.ItemCount = order.OrderLineItems.Count;
m.Items = order.OrderLineItems.ToList();
return View(m);
}
public async Task<ActionResult> AddItem(int productId)
{
var product = _context.Products.FirstOrDefault(p => p.ProductId == productId);
var order = FindOrCreateOrder();
var item = order.OrderLineItems.FirstOrDefault(i => i.ProductId == productId);
if (item != null)
{
item.Quantity++;
await _context.SaveChangesAsync();
}
else
{
item = new OrderLineItem();
item.OrderHeader = order;
item.Product = product;
item.Quantity = 1;
item.UnitPrice = product.Price;
order.OrderLineItems.Add(item);
await _context.SaveChangesAsync();
}
return RedirectToAction("Cart");
}
private OrderHeader FindOrCreateOrder()
{
var UserName = this.User.Identity.Name;
var user = UserManager.FindByName(UserName);
var customer = _context.Customers
.Include(c => c.OrderHeaders.Select(o => o.OrderLineItems.Select(i => i.Product))).
FirstOrDefault(c => c.UserId.Equals(user.Id));
var order = customer.OrderHeaders
.OrderBy(o => o.OrderDate)
.LastOrDefault(o => o.Paid == false);
if(order == null)
{
order = new OrderHeader();
//var Customer = new Customer();
order.Customer = customer;
customer.OrderHeaders.Add(order);
_context.SaveChanges();
}
return order;
}
}
}
This is the view model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SophicCeramics.Models.Order
{
public class Cart
{
public int ItemCount { get; set; }
public DateTime Date { get; set; }
public decimal Total { get; set; }
public List<OrderLineItem> Items { get; set; }
public decimal UnitPrice { get; set; }
public int OrderHeaderId { get; set; }
public string CustomerId { get; set; }
public System.DateTime OrderDate { get; set; }
public bool Paid { get; set; }
public int OrderLineItemId { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
public int CategoryId { get; set; }
public int ArtistId { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public string ProductArtUrl { get; set; }
public string ProductArtMain { get; set; }
public string UserId { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
}
}
And this is the view:
@model SophicCeramics.Product
@{ ViewBag.Title = "Cart"; }
<div>
<h4>Product</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Price)
</dt>
<dd>
@Html.DisplayFor(model => model.Price)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ProductArtUrl)
</dt>
<dd>
@Html.DisplayFor(model => model.ProductArtUrl)
</dd>
<dt>
@Html.DisplayNameFor(model => model.ProductArtMain)
</dt>
<dd>
@Html.DisplayFor(model => model.ProductArtMain)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Artist.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Artist.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Category.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Category.Name)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.ProductId }) |
@Html.ActionLink("Back to List", "Index")
</p>
The View has a layout page that is automatic. I keep getting the error pointing to this line of code:
var customer = _context.Customers
.Include(c => c.OrderHeaders.Select(o => o.OrderLineItems.Select(i => i.Product))).
FirstOrDefault(c => c.UserId.Equals(user.Id));
No matter how I rearrange the include statement it just won't work. Also, the controller is inheriting from another one called BaseController which has a connection to the database through _context. I've also tried adding pretty much everything from the relevant classes in the .tt files in the edmx, and still get the error. Also, when I put a break point on the customer variable and step through it, it goes straight to the dispose method in the BaseController.
I would guess that
user
is null, so you get the error when accessinguser.Id
inside a lambda expression hereYou need to check if
user
is null after this lineand only execute the rest of the code inside
FindOrCreateOrder
method whenuser
is not null. You also need to decide what to do ifuser
is null in theelse
block as follows