nullreferenceexception when accessing ViewData - c#

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...)

Related

Why asp-for input tag helper always use form data instead of the viewmodel?

My goal is, when a form is submitted, to be able to display the form again, but with a modified model, where I replace some values.
Take this simplified code for example:
public class IndexController : Controller
{
[HttpGet("")]
public IActionResult Index()
{
return View(new IndexViewModel() { Origin = "GET" });
}
[HttpPost("")]
public IActionResult Index(IndexViewModel viewModel)
{
viewModel.Origin = "POST";
viewModel.Name = "Fixed Name"; // I want to force this value
return View(viewModel);
}
}
public class IndexViewModel
{
public string Name { get; set; }
public string Origin { get; set; }
}
The following view:
#model IndexViewModel
<html>
<body>
<form method="post">
Name : <input asp-for="Name" /><br />
Origin : #Model.Origin
<br />
<button type="submit">Submit</button>
</form>
</body>
</html>
When I submit the form, the method goes through the POST method, but the view HTML only use the original form values.
The value "Fixed Name" is ignored and never used when rendering the view.
I suppose the asp-for tag helper always give higher priority to FormCollection values. Is there a way to force the use of the Model value ?
I cant answer why this happens, possibly someone more knowledgable can, but I've had to use the Post-Redirect-Get pattern:
[HttpPost("")]
public IActionResult Index(IndexViewModel viewModel)
{
viewModel.Origin = "POST";
// persist model or use TempData
return RedirectToAction("AfterPost");
}
public IActionResult AfterPost()
{
// get model or retrieve from TempData
viewModel.Name = "Fixed Name"; // I want to force this value
return View(viewModel);
}

MVC4 cshtml page function call

I need to display a value in an editable textbox on my mvc page when it first loads if it exists. I've got a function that will take care of getting the value that I need, but I need to pass in parameters from the current model to get what I need from the database.
The problem I'm having is getting this value into the textbox. What I tried was
cshtml:
#Html.TextBoxFor(model => model.AdjustedLiabilityAmount, new { #Value=OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetLatestAdjustedLiabilityAmount(Model.DOTNumber, Model.LiabilityAmount))}
I get a red squiggly that "The name 'Value' does not exist in the current context"
So I tried a different technique I read about which was like this.
Controller:
public ActionResult Index()
{
ViewBag.AdjustedValue = OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetLatestAdjustedLiabilityAmount(Model.DOTNumber, Model.LiabilityAmount);
cshtml:
#Html.TextBoxFor(model => model.AdjustedLiabilityAmount, new { #Value=ViewBag.AdjustedValue)}
This time I'm getting the red squiggly "The name 'Model' does not exist in the current context."
I'm sure I'm just missing something basic here as I'm new to MVC.
Any help is much appreciated.
Entire ActionResult Index:
public ActionResult Index()
{
ViewBag.AdjustedValue = OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetLatestAdjustedLiabilityAmount(Model.DOTNumber, Model.LiabilityAmount);
var Report = new OBS_LIB.DTO.JeopardyAssessmentReport();
Report.Stage = 1;
Report.Status = "Active";
Report.ReportItems = OBS_LIB.BLL.JeopardyAssessment.JeopardyAssessment.GetJAReportItems(Report.Stage, Report.Status);
return View(Report);
}
You want to do something like this:
Class:
public class ModelClassHere {
public float Liability {get;set;}
}
Controller:
public ActionResult Index(ModelClassHere model) {
model.Liability = 10.00;
return View(model); // pass model to the view
}
View:
#Html.TextBoxFor(x => x.Liability) // 'x' can be anything
EDIT*
If you already have a model and need to pass one simple value:
Controller:
public ActionResult Index(ModelClassHere model, string otherValue) {
model.Liability = 10.00;
ViewBag.Liability = model.Liability;
return View(model); // pass model to the view
}
View:
<input type="text" id="otherValue" name="otherValue" value="#ViewBag.Liability.ToString()" />
You can use
#Html.TextBox("AdjustedLiabilityAmount", (Decimal)ViewBag.AdjustedValue)}
Or
#Html.TextBox("AdjustedLiabilityAmount", Model.AdjustedLiabilityAmount == null ? (Decimal)ViewBag.AdjustedValue : Model.AdjustedLiabilityAmount)}
In decimal type you put your the type that you need.
You need to pass your model in the
Controller
return view(myModelName);
make sure you have access to it in your controller.
also your view has to reference the model in the #model line at the top.
Finally to call the model it would be
view:
Model.myModelName

Value not being passed properly to controller from view

I have an MVC application that when a link is clicked a page needs to be displayed based on the same values on another page. I can't figure out why what's getting passed is null instead of the string. My code is below.
Controller:
public string searchQ
{
get { return (string)Session["searchQ"]; }
set { Session["searchQ"] = value; }
}
public ActionResult Index()
{
Session["InitialLoad"] = "Yes";
return View();
}
[HttpPost]
public ActionResult Index(string heatSearch)
{
ViewBag.SearchKey = heatSearch;
searchQ = heatSearch;
return View();
}
public ActionResult Index_Perm()
{
ViewBag.SearchKey = searchQ;
return View();
}
public ActionResult PartialMainLim(string heatSearch)
{
HomeModel C = new HomeModel();
ChemViewModel D = new ChemViewModel();
D = C.QueryResults(heatSearch);
return PartialView(D);
}
public ActionResult PartialMain(string heatSearch)
{
HomeModel C = new HomeModel();
ChemViewModel D = new ChemViewModel();
D = C.QueryResults(heatSearch);
return PartialView(D);
}
The code in the index view looks like this (this one works):
#if (ViewBag.SearchKey != null)
{
<div>
#Html.Action("PartialMainLim", "Home", (string)ViewBag.SearchKey)
</div>
}
And in the index_perm view:
#if(ViewBag.SearchKey != null)
{
<div>
#Html.Action("PartialMain", "Home", (string)ViewBag.SearchKey)
</div>
}
When I check the value of SearchKey in both views it is correct. However for the method "PartialMain" null gets passed instead of the string, despite SearchKey being correct. This all works for the other view though. What am I doing wrong?
When passing values back to controller you have basically two options:
Make a form
Pass it as part of the url
Get methods only accept url attributes while Post methods are able to handle form content as well.
From what you are trying to do I'd say you could use something like:
#Html.Action("PartialMain", "Home", new {heatSearch = (string)ViewBag.SearchKey})
this should create url looking like /Home/PartialMain?heatSearch=[content of SearchKey]
EDIT:
That will only pass the value given it is present in the ViewBag. You are getting it from the Session which is imho a terrible idea in MVC (which should be session-less). Please consider if you really need it there. Usually there are other ways to implement this.
There is no HttpPost handler in the controller when you click the index_perm view.
I think that problem is your session that would be null. One of principles of framework ASP.NET MVC is stateless. Using session in ASP.NET MVC quite horrible.
At the moment, I think you can quickly fixed it by using TempData that default using Session under the hood. You could have a look an outdated article for further digging up ViewData vs TempData

How does my view know what type of data is being returned using MVC?

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)
}

MVC3 writing LINQ in Model

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.

Categories

Resources