It is said that the models should be fat and the Views should be thin.We put our business logic inside the Model (https://stackoverflow.com/questions/235233/asp-net-mvc-should-business-logic-exist-in-controllers).We normally write the LINQ inside the controller,but is it possible that we should write the query in models,If yes then how we will get the results in the View?
Second Question
public ActionResult Index()
{
using (NORTHWNDEntities c = new NORTHWNDEntities())
{
var x = c.Employees.Count();
ViewData["count"] = x;
return View(x);
}
}
When we do this are we passing the variable x to the View?
I tried to access the ViewData in View
<% ViewData["count"] %>
But it gives an error error ,Anyone who can help me with this
Thanks
If you are trying to display the value of ViewData["count"] in your view, you can use the following syntax:
<%= ViewData["count"] %>
Note the = in the opening tag. This is the equivalent of
<% Response.Write(ViewData["count"]) %>
there is better approach for doing this.and is very straight forward.create a Model that meets your needs and pass it to view.
public class MyModel
{
public int Count{get;set;}
}
and your controller can looks like
public ActionResult Index()
{
using (NORTHWNDEntities c = new NORTHWNDEntities())
{
var x = c.Employees.Count();
var model = new MyModel{Count = x};
return View(model);
}
}
and then create an strongly typed view
Razor Syntax :
#model MyModel
#Model.Count
ASPX syntax :
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.MyModel>" %>
<%= Model.Count %>
and the code can get even better if you do the following:
public class EmployeeService
{
public int GetEmployeeCount()
{
using (NORTHWNDEntities c = new NORTHWNDEntities())
{
var count = c.Employees.Count();
return count;
}
}
}
and the controller most change as well:
public ActionResult Index()
{
EmployeeService srvc = new EmployeeService();
var x = srvc.GetEmployeeCount();
var model = new MyModel{Count = x};
return View(model);
}
The query have to be into the Data Access Layer and the logic in MVC is into the Controller, not into the Model.
Here you can find an example of a layered architecture with MVC.
At the end you have always to use a Model into the View, don't pass data using the ViewData.
Related
I am in the habit of using nested loops in classic. Data from the first record set is passed to the second record set. How would I accomplish the same thing in MVC? As far as I can tell, I can only have one model passed to my view.
<%
rs.open "{Call usp_SalesOrder}",oConn
Do While (NOT rs.EOF)
%>
<div><% = rs("SalesOrderNumber")%></div>
<%
rs2.open "{Call usp_SalesOrderLines(" & rs("SOKey") & ")}",oConn
Do While (NOT rs.EOF)
%>
<div><% = rs2("SalesOrderLineNumber")%></div>
<%
rs2.MoveNext
Loop
rs2.close
%>
<%
rs.MoveNext
Loop
rs.close
%>
My suggestion would be to build a more robust model. It is true that you can only pass one model to your view, but your model can contain the results of multiple data sets, provided you have gathered those data sets in your controller and assigned them to the model.
I also suggest staying away from the ViewBag. It's an easy trap to fall into. Trust me when I say you'll regret it later.
For your example, maybe a model defined like this:
public class MyModel
{
public List<SalesOrder> SalesOrders = new List<SalesOrder>();
}
public class SalesOrder
{
public string SOKey = string.Empty;
public List<SalesOrderLine> SalesOrderLines = new List<SalesOrderLine>();
}
And the code to populate the sales orders in the controller:
public Action Index()
{
MyModel model = new MyModel();
model.SalesOrders.AddRange(CallUspSalesOrder());
foreach (SalesOrder salesOrder in model.SalesOrders)
{
salesOrder.SalesOrderLines.AddRange(CallUspSalesOrderLines(salesOrder.SOKey));
}
return View(model);
}
That way, you have access to all sales orders (and their sales order lines) within the view.
I would say that Nathan's post is a good start. Here is what I would do from beginning to end.
This is how I would do my model:
public class SalesOrderModel
{
public List<SalesOrderLines> SOLines = new List<SalesOrderLines>();
public List<SalesOrder> SOHeader = new List<SalesOrder>();
}
My Controller would then do this:
public ActionResult Index()
{
List<SalesOrder> SalesOrder = callSalesOrderUSP.ToList();
List<SalesOrderLines> SalesOrderLines = new List<SalesOrderLines>();
foreach (var thing in SalesOrder)
{
SalesOrderLines.AddRange(callSalesOrderLinesUSP(thing.SOKey).ToList());
}
SalesOrderModel salesOrderModel = new SalesOrderModel
{
SOHeader = SalesOrder,
SOLines = SalesOrderLines
};
return View(salesOrderModel);
}
Then in your view you can do this:
#foreach(var something in Model.SOHeader)
{
foreach (var thing in Model.SOLines.Where(i => i.SOKey == something.SOKey))
{
//display info here
}
}
You can use ViewBag to pass elements not relevant to your model. Also do not be afraid of creating your own ModelView objects that can work between your View and Controller. Your views should not be restricted to what your model has to offer.
Take a look at this for how you can implement a ViewModel in MVC.
And perhaps look at this to see how you can use ViewBag to pass values to your view, not relevant to your model.
I am new to mvc and cannot figure out how to pass a single column of data to the view.
I have connected my db with ado.net entity model to models.
Then in my controller I have :
public class HomeController : Controller
{
shdesignEntities2 _db;
public ActionResult Index()
{
_db = new shdesignEntities2();
ViewData.Model = _db.tblKategoris.ToList();
return View();
}
}
In the view :
#foreach(var m in ViewData.Model)
{
<p>Kategori Ad :</p><p> #m.kategori_ad </p>
}
When I do like this , I pass the whole table data to the view where I only need a single column of information.
How can I only pass data from the column kategori_ad ?
Use Select:
ViewData.Model = _db.tblKategoris.Select(x => x.kategori_ad).ToList();
You can use LINQ to find the object that you want and then pass it to the view, do something like this:
public ActionResult Index()
{
_db = new shdesignEntities2();
ViewData.Model = _db.tblKategoris.Select(x => x.kategori_ad).ToList();
return View();
}
That way ViewData.Model only has the object that matches the linq query.
Here you can find more about Linq to retrieve data from a collection in C#: http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
In Controller
ViewData["Rows"] = (from c in _db.tblKategoris
select c.kategori_ad).ToList();
View
#foreach(var m in (List<string>)ViewData["Rows"])
{
<p>Kategori Ad :</p><p> #m </p>
}
You may look at ViewModels. Also by this way you can use smaller part of data exposed.
For example
public class KategoriViewModel
{
public IEnumerable<Kategori> Kategoriler { get; set; }
}
Then you should add a controller action like
public ActionResult Something()
{
var model = new KategoriViewModel;
model.Kategoriler = your query..;
return View(model);
}
In view
#model KategoriViewModel
#foreach(var m in ViewData.Model)
{
<p>Kategori Ad :</p><p> #m.kategori_ad </p>
}
I have a asp.net MVC4 web project it shows a list of production data for that day. I have added a datetime picker which allows the user to select a date that they want to show information for.
The problem i am having is i am not sure how to go about passing the information back to the view from the method i have inside the controller.
I have the date passing back to the controller. Inside the controller i am doing a LINQ statement that allows me to select only the production data for that day.
[HttpPost]
public ActionResult GetProductionDateInfo(string dp)
{
DateTime SelectedDate = Convert.ToDateTime(dp);
DateTime SelectedDateDayShiftStart = SelectedDate.AddHours(7);
DateTime SelectedDateDayShiftEnd = SelectedDate.AddHours(19);
var ProductionData =
from n in db.tbl_dppITHr
where n.ProductionHour >= SelectedDateDayShiftStart
where n.ProductionHour <= SelectedDateDayShiftEnd
select n;
return View();
I am looking to get the Var ProductionData passed back to the view so that display it inside a table.
You can return ProductionData directly to your View.
return View(productionData)
And then in your View you could have #model IEnumerable<Type>
However, a better practice would be to create a strongly typed ViewModel to hold the ProductionData and then return the following:
var model = new ProductionDataViewModel();
model.Load();
return View(model);
Where model a definition as follows:
public class ProductionDataViewModel {
public List<ProductionDataType> ProductionData { get; set; }
public void Load() {
ProductionData = from n in db.tbl_dppITHr
where n.ProductionHour >= SelectedDateDayShiftStart
where n.ProductionHour <= SelectedDateDayShiftEnd
select n;
}
}
Then in your view use the new strongly typed ViewModel:
#model ProductionDataViewModel
Use a model, something like:
public class ProductionDataModel
{
//put your properties in here
public List<ProductionData> Data { get; set; }
}
Then create/return it in your ActionResult:
var ProductionData =
from n in db.tbl_dppITHr
where n.ProductionHour >= SelectedDateDayShiftStart
where n.ProductionHour <= SelectedDateDayShiftEnd
select new ProductionData
{
//set properties here
};
var model = new ProductionDataModel
{
Data = ProductionData
};
return View(model);
Then in your view, set your model at the top:
#model ProductionDataModel
Your ProductionData variable should now be of type IEnumerbable<tbl_dppITHrRow>.
You can pass in the model from your controller using this code at the bottom of your action:
return View(ProductionData);
In your view, you can make this your model type by placing the following Razor code in your view's .cshtml file:
#model IEnumerbable<tbl_dppITHrRow>
Then, you can use your model in your view code:
#foreach(var row in Model) {
<div>#row.Value</div>
}
The problem here is that you are returning nothing to your view here return View(); this view just render view and no data will be passed to it.
if ProductionData is getting values then
return return View(ProductionData);
You can then use the values passed in the view.
So I created a project to test DI in MVC 4. Yeah, that was the easy part. I have a controller that looks like this.
public class CompanyManagementController : Controller
{
private ICompanyService companyService;
public CompanyManagementController(ICompanyService companyService)
{
this.companyService = companyService;
}
public ActionResult Index()
{
return View(companyService.GetCurrentCompanies());
}
}
What I can't figure out is how to tell the view Index.cshtml that I have this List that I am returning to it. When I have just a POCO it's easy. I did this
[HttpGet]
public ActionResult Create()
{
var company = new Company();
return View(company);
}
[HttpPost]
public ActionResult Create(Company company)
{
using(var context = new InventoryContext())
{
context.Companies.Add(company);
context.SaveChanges();
}
return View("Create");
}
That was super easy because I just said
#model MvcInventoryManager.Models.Company
in the Create.cshtml file.
Any hints? What I want to do is be able to loop through the list of companies that get returned.
Thanks!
What is the return type of companyService.GetCurrentCompanies()? That would be the type you'd want to use for binding the Model in the view. For example, if the type is IEnumerable<Company> then in your view you would declare this:
#model IEnumerable<MvcInventoryManager.Models.Company>
That way the type of the Model property would match what's being passed to the view and you could loop through the Model:
foreach (var company in Model)
after declaring your model in the view just loop through it like so:
#foreach (var company in Model)
{
Html.DisplayFor(modelItem => company.companyID)
Html.DisplayFor(modelItem => company.CompanyName)
}
Controller
public class DashboardController : Controller
{
//
// GET: /Dashboard/
public ActionResult Index()
{
ViewData["PartnerID"] = GetPartnerID();
return View();
}
public ActionResult OutboundTransfers()
{
var partnerId = ViewData["PartnerID"].ToString();//NULL EXCEPTION
InventoryEntities context = new InventoryEntities();
var result = context.GetOutboundTransfers(partnerId);
//var result = context.GetOutboundTransfers("3000017155");
return View(result);
}
private static string GetPartnerID()
{
return "3000017155";
}
}
}
View (Dashboard/Index)
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
<%= Html.Action("OutboundTransfers")%>
</asp:Content>
I am a beginner to MVC 2. I read the ViewData should be accessible to the partial view (OutboundTranfers.ascx) as a copy. So, why do I get a null reference here?
Instead of setting ViewData["PartnerID"] in Index(), try creating a constructor for your controller and setting the value there like so:
public DashboardController()
{
ViewData["PartnerID"] = GetPartnerID();
}
ViewData is presumably not null -- ViewData["PartnerID"] is null. (the item is not in the ViewData) Also, you set the PartnerID data in one action, and fetch it in the other. ViewData is not preserved across requests/actions.
(Moved out of comments into an answer...)