1

I have made a webapp where you search by client id, and then adds orders on that client. The index action method assigns the chosen client to the viewmodel(vm.AllClients). The order table of course has information about the client. In the Insert method i want to use the information about the chosen client, but now vm.AllClients is returning null.

During debugging vm.AllClients is filled with one client object, as it should, during the running of the first method. When the second method is running vm.AllClients is empty.

I have tried to save the search string as a variable and find it in the db(Not a good solution), but the variable is also empty during the running of the second method. Also tried to save the chosen client as a Client object in the viewmodel, still no dice.

AddController

using MainWeb.Models;

public class AddController : Controller
    {
        OrderEntities db = new OrderEntities();// New instance of db.
        ViewModel vm = new ViewModel();//New instance of viewmodel


[HttpPost]
        public ActionResult Index(string searchTerm)
        {
            if (string.IsNullOrEmpty(searchTerm))
            {
                vm.AllClients = new List<Client>();
            }
            else
            {
                vm.AllClients = db.Clients.Where(x => 
                x.RefNo.ToString().Equals(searchTerm)).ToList();

                foreach (Client client in vm.AllClients)
                {
                    vm.ThisClient = client;//Attempt at a different solution
                    break;
                }

            }
                return View(vm);
        }


public ActionResult InsertOrder(FormCollection form)
        {
            Order order = new Order();

            order.ClientID = vm.AllClients[0].ID;//Here is where the error gets thrown
            return RedirectToAction("Index");
        }

View

@model MainWeb.Models.ViewModel

    <div class="card border-primary mb-3 card-client" style="max-width: 40rem;">
        <div class="card-header">Legg til</div>
        <div class="card-body">
            <div class="editor-label">
                <table>
                    @using (Html.BeginForm("Test", "Add", FormMethod.Post))
                    { 
                    <tr>
                        <td>@Html.Label("Velg Prosjekt:")</td>
                    </tr>
                    <tr>
                        <td>
                            @Html.DropDownList("fromDBProjects", (IEnumerable<SelectListItem>)ViewData["DBProjects"], new { @class = "form-control" })
                        </td>
                    </tr>
                    <tr>
                        <td>@Html.Label("Velg Produkt:")</td>
                    </tr>
                    <tr>
                        <td>
                            @Html.DropDownList("fromDBProducts", (IEnumerable<SelectListItem>)ViewData["DBProducts"], new { @class = "form-control" })
                        </td>
                    </tr>
                    <tr>
                        <td>@Html.Label("Pris:")</td>
                    </tr>
                    <tr>
                        <td><input type="submit"  value="Submit" class="btn btn-primary" id="btn-search" /></td>
                    </tr>
                    }
                </table>
            </div>
        </div>
    </div>
</div>
}

ViewModel

namespace MainWeb.Models
{
    public class ViewModel
    {
        public List<Client> AllClients { get; set; } 
        public Client ThisClient { get; set; }

    }
}

Error:

Object reference not set to an instance of an object
tereško
  • 58,060
  • 25
  • 98
  • 150
CSP
  • 53
  • 10

2 Answers2

1

In general I asume you are trying to write an new asp.net web application. But you should consider using asp.net core. This framework is the followup of asp.net mvc and you shouldn't start coding asp.net core mvc instead of the full framework. That is deprecated and will get replaced by asp.net core mvc

I guess you should do the mvc tutorial from MS first. To get a better understanding how everything works. https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/?view=aspnetcore-2.2

But now to your question: There are a couple of issues in your example:

  1. ViewModel shouldn't be a central class. Create it in your Controller Action, because every webrequest get's a new instance of your controller!
  2. When you hit "InsertOrder" - the controller is created newly for the new request. Which means you get a new instance of the controller and your viewModel is empty again
  3. Your cshtml will never hit your "InsertOrder"
  4. InsertOrder can map your formcollection directly into a class.
  5. Minor: you shouldn't layout your html with a table - See: Why not use tables for layout in HTML?

Your controller should look like this

public class AddController : Controller
    {
        OrderEntities db = new OrderEntities();// New instance of db.



[HttpPost]
        public ActionResult Index(string searchTerm)
        {
            var vm = new ViewModel();
            if (string.IsNullOrEmpty(searchTerm))
            {
                vm.AllClients = new List<Client>();
            }
            else
            {
                vm.AllClients = db.Clients.Where(x => 
                x.RefNo.ToString().Equals(searchTerm)).ToList();

                foreach (Client client in vm.AllClients)
                {
                    vm.ThisClient = client;//Attempt at a different solution
                    break;
                }

            }
                return View(vm);
        }

[HttpPost]
public ActionResult InsertOrder(ViewModel vm)
        {
            Order order = new Order();

            order.ClientID = vm.AllClients[0].ID;//Here is where the error gets thrown
            return RedirectToAction("Index");
        }

And your view should set the form to this:

 @using (Html.BeginForm("InsertOrder", "Add", FormMethod.Post))
Bjego
  • 665
  • 5
  • 14
  • So the only difference you made was using the ViewModel as a parameter? – CSP Sep 03 '19 at 09:17
  • I think so. But you should have a look at the whole lifecycle @CSP and maybe get a bit more famliar with the web mvc technology in general ;) – Bjego Sep 03 '19 at 10:05
  • I got it working using TempData, probably bad practice though. Its my first MVC webapp, trying to learn, thanks :) – CSP Sep 03 '19 at 10:31
  • good luck - the tutorial I linked is very good. And you should use asp.net core (platform independend, dependency injection,... ) ;) – Bjego Sep 03 '19 at 10:56
0

Each request gets a fresh controller instance, so you cannot use the global Viewmodel variable. If you want to communicate between controller actions use ViewData object or simply send the data to the client and get it via FormCollection or your ViewModel class.

harmath
  • 183
  • 5
  • His was more in-dept, but it got it working with TempData, pretty close to ViewData so, dont really know who to give it to. Thanks to both of you for taking the time! :) – CSP Sep 03 '19 at 13:17