I'm passing 3 sets of data through to a view in a viewmodel and have a problem relating one of them to the other two in my foreach coding:
My DB tables are:
"ServiceGroups" is parent to "Services"
"Services" is related through a joining table (using a 2 composite Primary Key) to the aspnet_users table (I call "Users")
I pulled this into an EF model called GWServices.edmx
so now I have 3 entities related like so:
ServiceGroup (parent to) Service
Service (many to many with) User
Then I created a controller and a viewmodel like this:
{
public class ServicesViewModel
{
public ServicesViewModel(List<ServiceGroup> servicegroups, List<Service> services, List<User> aspnetusers)
{
this.ServiceGroups = servicegroups;
this.Service = services;
this.AspnetUsers = aspnetusers;
}
public List<ServiceGroup> ServiceGroups { get; set; }
public List<Service> Service { get; set; }
public List<User> AspnetUsers { get; set; }
}
public class ClientServicesController : Controller
{
public ActionResult Index()
{
GWEntities _db = new GWEntities();
var servicegroups = _db.ServiceGroupSet.ToList();
var services = _db.ServiceSet.ToList();
var aspnetusers = _db.UserSet.ToList();
return View(new ServicesViewModel(servicegroups, services, aspnetusers));
}
}
}
Next I created the view with 3 foreach loops to:
Get and present as a UL, a list of all service groups in the database (which worked)
Populate a table under each Servicegroup filling down some Service data for each Service within that given group (which also work)
Test whether the user is associated with this particular Service, if so show only the red cross icon, otherwise show the green "select me" icon. (this doesn't populate any users)
So the code looks like this:
<% foreach (var servgroup in Model.ServiceGroups) { %>
<ul> <%= servgroup.ServiceGroupName%> </ul>
<table>
<% foreach (var serv in servgroup.Service)
{ %>
<tr>
<td class="td1">
<%= serv.ServiceDescription%>
</td>
<td class="td2">
<% = Html.Encode(String.Format("{0:f}",serv.MonthlyPrice)) %>
</td>
<td class="td3">
<%foreach (var user in serv.User) {%>
<%if (user.UserName == User.Identity.Name)
{ %>
<img src="/Content/LightRedCross_2.png" alt="" height="15px" width="15px"/>
<% }
else
{%>
<img src="/Content/LightGreenAdd_2.png" alt="" height="15px" width="15px"/>
<%} %>
<%} %>
</td>
</tr>
<% } %>
</table>
<% } %>
Can anyone tell me why foreach(var user in serv.user) does not recognise that "Customer1" (the currently logged in user) has 6 services ordered (as it is in the joining table)?
Thanks!
Paul
Looking at your code I think this could be resolved by loading the child tables of ServiceGroups.
It is likely that the Services & User reference was not loaded in the original Entity Framework query. Therefore, as you are trying to iterate through the children in the foreach loop, it does not see a collection, it just sees null.
You should try altering your retrieval statements:
_db.ServiceGroupSet.ToList()
to
_db.ServiceGroupSet.Include("ServiceSet").Include("UserSet").ToList()
If this doesn't fix your issue, I would put a break point on the below line of code and traverse the List to see if it has the data you expect.
this.ServiceGroups = servicegroups;
For starters, username comparisons are generally case-insensitive. So this:
<%if (user.UserName == User.Identity.Name)
...should be:
<%if (user.UserName.Equals(User.Identity.Name, StringComparison.OrdinalIgnoreCase))
You also have a bug where you don't dispose your entity context. You should override Controller.Dispose and dispose it there. This allows the view to render before the context is disposed.
Related
A few months back, there was a job position who required a pre interview task assessment. I'm actually new to .NET, so I passed and decided to apply to another job which didn't require .net as much. Long story short. Since then, the idea of solving this problem hunts me and It bothers me that I was able to get really close to the solution and didn't actually finished it.
So, if anybody wants to practice their .net /webapi2/ angular skills here it is:
screenshot
I get a weird error (NULL values) when I'm almost finishing this task
My Homecontroller.cs
namespace KLab.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Title = "Home Page";
return View();
}
public JsonResult GetSections()
{
var db = new KLabDBEntities();
var samples = db.Samples.Include("User").Include("Status").ToList();
return Json(samples, JsonRequestBehavior.AllowGet);
}
}
}
Since this is WEb API I've changed the angular code to the following:
my App.js
var myApp = angular.module('myApp', []);
myApp.controller('maincontroller', function ($scope, SampleService) {
getSamples();
function getSamples() {
SampleService.getSamples()
.success(function (Samples) {
$scope.Samples = Samples;
});
}
});
my service.js
myApp.factory('SampleService', ['$http', function ($http) {
var urlBase = 'http://localhost:35656/api';
var SampleService = {};
SampleService.getSamples = function () {
return $http.get(urlBase + '/Samples');
};
return SampleService;
}]);
My index.cshtml
<h2>Samples</h2>
<div ng-controller="maincontroller">
<table class="table">
<tr>
<th>Samples Id </th>
<th>Code Number</th>
<th>Date </th>
<th>User Id </th>
<th>Status Id </th>
</tr>
<tr ng-repeat="Sample in Samples">
<td>{{Sample.SampleId}} </td>
<td>{{Sample.CodeNumber}} </td>
<td>{{Sample.Date.replace('/Date(','').replace(')/','') | date:"MM/dd/yyyy"}} </td>
<td>{{Sample.UserId}}</td>
<td>{{Sample.StatusId}}</td>
</tr>
</table>
</div>
Everything else is default from the WeBAPI2 template from Visual Studio.
so my Models are generated by Entity Framework:
When I build i get:
Samples Id CodeNumber Date UserId StatusId
data data data 1 6
data data data 2 4
My goal is to change those id numbers to the actual data of the tables , they are foreign key values
I get no values in that column and when I call the JSON I get:
[{"SampleId":1,"CodeNumber":129076,"Date":"2015-01-02T00:00:00","UserId":6,"StatusId":3,"Status":null,"User":null},
{"SampleId":2,"CodeNumber":850314,"Date":"2015-06-15T00:00:00","UserId":7,"StatusId":3,"Status":null,"User":null},
{"SampleId":3,"CodeNumber":176033,"Date":"2015-07-31T00:00:00","UserId":7,"StatusId":0,"Status":null,"User":null},
{"SampleId":4,"CodeNumber":129629,"Date":"2015-01-21T00:00:00","UserId":3,"StatusId":0,"Status":null,"User":null},"
which is odd since , Status and user are null
Somebody has suggested that this "joins" must be done within a view on the Database itself and then should be called with angular. like a SQL view or using LINQ. Unfortunately, I do not know LINQ but I do know SQL I guess I can create a view with all the tables. Therefore the question is. How can i replace those ID values to the actual data that are related to those foreign keys (userid, statusid) ?
Here's the bulk data's screenshot:
bulk data
How can I get the data which is bottom left hand side of the image from view to controller when I press to submit button ?
Link for image
public ActionResult EnterInformation1()
{
// the ??? is the data from the view;
TempData['abc'] = ???
return RedirectToAction("Paper");
}
I did look up reference before I ask.thanks
If you want to send data from view to controller all you need is to do next step:
1) Send data from controller to view. For example you want to display the content of a model wich is List
public ActionResult ShowList()
{
List<string> lst = new List<string>() {"1", "2", "3", ,"4"};
return View("MyListView", lst);
}
2) Display this data on the View using html helpers with postfix "for" (for example, textBoxFor, hiddenFor, EditorFor, DisplayFor...) and place them inside form tag
#model List<string>
<form action="GetDataFromView" method="post">
<table>
<tr>
<th>some header</th>
<tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(m=> item)
</td>
</tr>
}
</table>
</form>
3) Write Method in controller wich will get these data
public ActionResult GetDataFromView(List<string> model)
{
//do what you want with data sended from view to controller
// which stored in parameter model
return View("someView");
}
So I am following the example at http://holsson.wordpress.com/2011/08/24/microsoft-dynamics-crm-2011-online-integration-getting-started-late-bound/ to try and create an MVC 5 site that uses CRM as the backing data. I created a CRMAccount Controller (Could't make one called Account as it was used by the Identity system).
I am able to successfully query the CRM System but when i try to use the Razor Code below in my view, I get the name, but nothing under the accountid is displayed. The item returned by accountid is a GUID, If I try to set it to a string, the DisplayFor complains that it can't render that.
#model IEnumerable<Microsoft.Xrm.Sdk.Entity>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<table>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item["accountid"])
</td>
<td>
#Html.DisplayFor(modelItem => item["name"])
</td>
</tr>
}
</table>
I am only doing this right now for Proof Of Concept. Eventually, I want to put the two together as a drop down box, but if I can't get the GUID to pull correctly, I'm going to have problems.
EDIT:-------------------------------------------------------------------
I was asked to post the controller code, though something similar was in the example i linked to above.
Here's the code used in my controller.
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
namespace ExternalEntities.Controllers
{
public class CRMAccountController : Controller
{
// GET: CRMAccount
public ActionResult Index()
{
var service = Session["ServiceProxy"] as IOrganizationService;
if (service != null)
{
var context = new OrganizationServiceContext(service);
IQueryable<Entity> query = from e in context.CreateQuery("account") select e;
List<Entity> accts = query.ToList();
return View(accts);
}
return RedirectToAction("Login", "Account");
}
}
}
try
#Html.DisplayFor(modelItem => item.accountid)
instead of
#Html.DisplayFor(modelItem => item["accountid"])
for intellisense, also can you show the controller please.
Edited after some comments back and forth:
Maybe you have a DisplayTemplate that is on your way? Try to do #item["accountid"] and see if it still blank. (not using DisplayFor)
I'm trying to recreate MVC Music Store but I've faced an error which I can't handle: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection". The error is related to the following line in the ShoppingCart Index view:
#Html.ActionLink(item.Product.Title, "Details", "Store", new { id = item.ProductId }, null)
ShoppingCartController:
public class ShoppingCartController : Controller
{
OnlineStoreDbContext db = new OnlineStoreDbContext();
//
// GET: /ShoppingCart/
public ActionResult Index()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
return View(viewModel);
}
//
// GET: /Store/AddToCart/5
public ActionResult AddToCart(int id)
{
// Retrieve the album from the database
var addedProduct = db.Products.Single(product => product.ProductId == id);
// Add it to the shopping cart
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCart(addedProduct);
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the album to display confirmation
string productName = db.Carts.Single(item => item.RecordId == id).Product.Title;
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(productName) + " has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
}
//
// GET: /ShoppingCart/CartSummary
[ChildActionOnly]
public ActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
ViewData["CartCount"] = cart.GetCount();
return PartialView("CartSummary");
}
}
ShoppingCart Index View:
#model OnlineStoreMVC.UI.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
// Document.ready -> link up remove event handler
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '') {
// Perform the ajax post
$.post("/ShoppingCart/RemoveFromCart", { "id": recordToDelete },
function (data) {
// Successful requests get here
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
function handleUpdate() {
// Load and deserialize the returned JSON data
var json = context.get_data();
var data = Sys.Serialization.JavaScriptSerializer.deserialize(json);
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
}
</script>
<h3>
<em>Review</em> your cart:
</h3>
<p class="button">
#Html.ActionLink("Checkout", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
Movie Title
</th>
<th>
Price (each)
</th>
<th>
Quantity
</th>
<th></th>
</tr>
#foreach (var item in Model.CartItems)
{
<tr id="row-#item.RecordId">
<td>
#Html.ActionLink(item.Product.Title, "Details", "Store", new { id = item.ProductId }, null)
</td>
<td>
#item.Product.Price
</td>
<td id="item-count-#item.RecordId">
#item.Count
</td>
<td>
Remove from cart
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
#Model.CartTotal
</td>
</tr>
</table>
Edit:
public class ShoppingCart
{
string ShoppingCartId { get; set; }
public const string CartSessionKey = "CartId";
public static ShoppingCart GetCart(HttpContextBase context)
{
var cart = new ShoppingCart();
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}
public static ShoppingCart GetCart(Controller controller)
{
return GetCart(controller.HttpContext);
}
}
This error means pretty much exactly what it says. Somewhere, you've disposed of your application context instance, and then tried to make another query with it. This happens frequently when you're misusing lazy loading and perhaps being a little over-eager with disposing your context (wrapping it in a using block) for example.
I'm not seeing any likely culprit in the code you posted but ShoppingCart.GetCart looks like a prime candidate for further investigation.
Basically, you want to do two things. First, you want to get a handle on what's actually being utilized by your action/views. If you're accessing related items to a cart, or something, then you should consider eager-loading those with Include. Second, you need to ensure that you context sticks around throughout the period it needs to be used. If you're lazy loading items in your view, and you intend to do that, then you'll need to make it last the life of the request: just don't use using and rely on the Dispose method of the controller for disposing of it.
That's generalized advice though. Since I believe your issue lies in this GetCart method, if that's actually the case, then you need to approach it slightly differently. First, you can ensure that GetCart returns a fully-baked result, that will not allow further querying. In cases where you're returning an enumerable, you can normally clear this up just by using .AsList(). Since this is likely just returning a single object, you would need to map it to a DTO or something: anything other than the actual entity class.
Your other option is to inject your context to the method. Normally, injecting into the class would be preferred, but it looks like you're dealing with a static class here. Basically, you want to allow your controller to create and dispose the context and then just pass it as a parameter to your GetCart method, so that it uses the context in the controller instead of creating its own. Depending on your applications needs, you might actually consider implementing some dependency injection framework to handle tasks like these.
I have an ASP.NET MVC project in C# using Forms Authentication and Active Directory is the Membership Provider (users login with their existing uid/pwd). However, I would like the roles to be supplied by aspnet_Roles (the default table created by the application). In my Web.config I have: with default setting for this node.
I successfully followed the NerdDinner sample application PDF and wish to use what I have learned. In my app I am using the Repository pattern just like NerdDinner. In NerdDinner, it shows how to use a Helper method to populate a DropDownList. I would like to do the same, but instead of countries and DropDown I would like to pull Roles from a table and populate check boxes.
In my UsersController.cs I have:
//
// ViewModel Classes
public class UserFormViewModel
{
// properties
public User User { get; private set; }
public SelectList Roles { get; private set; }
// Constructor
public UserFormViewModel(User user)
{
User = user;
Roles = new SelectList(Roles.All, ); //this is where I have problems
}
}
In my view I have (which of course will not work):
<ul>
<% foreach (var role in Roles as IEnumerable<SelectListItem>)) { %>
<li><%= Html.CheckBox(role.ToString())%> <%= role.ToString() %></li>
<% } %>
</ul>
P.S. I am a newbie to .NET, but I love it! Correct me if I am wrong, but I think this issue has to do with collections and type definitions?
Also, I am familiar with using the ASP.NET configuration tool to add Roles and Users, but I would like to create a custom User Admin section.
Something like this ?
<li><%= Html.CheckBox(role.ToString(),
Roles.IsUserInRole(Model.User.Identity.LoginName, role.ToString())) %>
<%= role.ToString() %>
</li>
Cant quite remember the exact syntax of the Roles in the asp.net membership provider, but it is something along those lines.
It looks like I do not need use the UserFormViewModel class. Morph helped me out. This is what I am doing:
<ul>
<%
string[] allroles = Roles.GetAllRoles();
foreach (string role in allroles) {
%>
<li>
<%= Html.CheckBox(role.ToString(), Roles.IsUserInRole(Model.UserName, role.ToString())) %>
<%= role.ToString() %>
</li>
<% } %>
</ul>