Nancy Object reference not set to an instance of an object - c#

I'm trying to display some information from a model to my view in Nancy.
Viewmodel
public class Fixtures
{
public int Id { get; set; }
public Users HomeUser { get; set; }
public Users AwayUser { get; set; }
}
Module
Get["/fixtures"] = _ =>
{
var model = new List<Fixtures>();
model.Add(new Fixtures() { Id = 1, HomeUser = new Users() { id = 1, Name = "Paddy" }, AwayUser = new Users() { id = 2, Name = "Dave" } });
model.Add(new Fixtures() { Id = 2, HomeUser = new Users() { id = 3, Name = "Scott" }, AwayUser = new Users() { id = 4, Name = "Chris" } });
return View["Fixtures", model];
};
View
#inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<System.Collections.Generic.List<Fifa.Leaderboard.Data.ViewModel.Fixtures>>
#{
Layout = "_Layout.cshtml";
}
<div id="fixtures">
#foreach (var fixture in Model)
{'
<p>#fixture.HomeUser</p>
<p>VS</p>
<p>#fixture.AwayUser</p>
}
</div>
Anyone know why I'm getting this error?

Problem was found as mentioned in comments of original question.
Nancy does not have a concept of a Shared Views folder like ASP.NET MVC.
The normal way to do this would be to put the _Layout.cshtml in the root of the /Views folder.
If you want to avoid the view being in the root folder or avoid specifying the full path, you can add a View Location to the list like so:
public class CustomConventionsBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
{
this.Conventions.ViewLocationConventions.Add((viewName, model, context) =>
{
return string.Concat("views/shared/", viewName);
});
}
}
Documentation can be found here:
https://github.com/NancyFx/Nancy/wiki/View-location-conventions#defining-custom-conventions

Related

ASP NET Core (MVC) problem with passing parameters from the view to the controller

I got a two DropDownList's in View. When i try pass those parameters, method in controller called but parameters equals a null.
When i check in browser (F12-network) i watch parameters - they are sended but in method still nulls
P.S.
I try change type of parameters on List or Location and JobTitle or CommonEntity, but its doesn't work
Controller:
public class HelloController: Controller
{
[HttpGet]
public IActionResult Index()
{
var locations = new List<Location>()
{
new Location()
{
Id = 0,
Title = "Russia"
},
new Location()
{
Id = 1,
Title = "Canada"
}
};
ViewBag.Location = locations;
var jobs = new List<JobTitle>()
{
new JobsTitle()
{
Id = 0,
Title = "Manager"
} ,
new JobsTitle()
{
Id = 1,
Title = "Programmer"
}
};
ViewBag.JobTitle = new SelectList(jobs, "Title", "Title");
return View();
}
[HttpPost]
public string Find(string answer1, string answer2)
{
return "Fine";
}
View:
#using Stargate.Core.Models.CoreEntities
#model CommonEntity
#using (Html.BeginForm())
{
#Html.DropDownListFor(m => m.Location.Title, new SelectList(ViewBag.Location, "Title", "Title"))
#Html.DropDownListFor(m => m.JobTitle.Title, new SelectList(ViewBag.JobTitle, "Title", "Title"))
<button type="submit">Find</button>
}
Models:
public class CommonEntity
{
public Location Location { get; set; }
public JobTitle JobTitle { get; set; }
}
public class JobTitle
{
public long Id { get; set; }
public string Title { get; set; }
}
public class Location
{
public long Id { get; set; }
public string Title { get; set; }
}
Because the parameter names you accept are answer1, answer2, you should have a matching name in your view to make it possible to bind successfully.
You can modify your front-end code as follows(DropDownListForto DropDownList):
#model CommonEntity
#using (Html.BeginForm("Find", "Hello"))
{
#Html.DropDownList("answer1", new SelectList(ViewBag.Location, "Title", "Title"))
#Html.DropDownList("answer2", new SelectList(ViewBag.JobTitle, "Title", "Title"))
<button type="submit">Find</button>
}
Your Controller:
public class HelloController : Controller
{
[HttpGet]
public IActionResult Index()
{
var locations = new List<Location>()
{
new Location()
{
Id = 0,
Title = "Russia"
},
new Location()
{
Id = 1,
Title = "Canada"
}
};
ViewBag.Location = locations;
var jobs = new List<JobTitle>()
{
new JobTitle()
{
Id = 0,
Title = "Manager"
} ,
new JobTitle()
{
Id = 1,
Title = "Programmer"
}
};
ViewBag.JobTitle = jobs;
return View();
}
[HttpPost]
public string Find(string answer1,string answer2)
{
return "Fine";
}
}
Class:
public class CommonEntity
{
public Location Location { get; set; }
public JobTitle JobTitle { get; set; }
}
public class JobTitle
{
public long Id { get; set; }
public string Title { get; set; }
}
public class Location
{
public long Id { get; set; }
public string Title { get; set; }
}
Result:
you are doing things wrongly,
you should correct your cshtml so that when submitting the form, it will target your Find Action,
#using (Html.BeginForm("Find", "Hello"))
In your Find Action you should provide in input args resolvable by the DefaultModelBinder, since you don't have a ViewModel to intercept the response, I would suggest that you recieve a FormCollection and you can access your values from there.
[HttpPost]
public string Find(FormCollection form)
{
return "Fine";
}
Try updating parameters as below. Please refer Model Binding in ASP.NET Core for more details.
[HttpPost]
public string Find(Location Location, JobTitle JobTitle)
{
return "Fine";
}
Or you can try with parameter of CommonEntity like below.
[HttpPost]
public string Find(CommonEntity commonEntity)
{
var locationTitle = commonEntity.Location.Title;
var jobTitle = commonEntity.JobTitle.Title;
return "Fine";
}

asp.net MVC How to add a Data object to IList method

I am creating a test project where i have products, i didn't won't to use a database at the beginning so i made Mocks Data that returns a list of products, but i want a user should be able to add to the list.
This is the Model
namespace StoreTest.Models
{
public class Products
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
}
This is the Mock data class
using System.Collections.Generic;
using StoreTest.Models;
namespace StoreTest.Data.Mocs
{
public class ProductMocks
{
public IList<Products> ProductList
{
get
{
return
new List<Products>
{
new Products
{
Id = 1,
Name = "Some Data",
Price = 34.00
},
new Products
{
Id = 2,
Name = "More Data",
Price = 28.00
}
};
}
}
}
}
This is the part from the Controller where i want to add to the ProductList
[HttpPost]
public IActionResult NewProduct(NewProductViewModel vm)
{
if (ModelState.IsValid)
{
Products product = new Products()
{
Id = vm.Id,
Name = vm.Name,
Price = vm.Price
};
ProductMocks addProduct = new ProductMocks();
// THIS IS NOT WORKING
productMocs.ProductList.Add(product);
return View("Index", addProduct);
}
else
{
return View(vm);
}
}
I am very new to asp.net.
Idon't know if i need to change the whole ProductMocks class, or i only need to add something in the controller?
Thank you in advanced!
Your ProductMocks implementation is not correct, as when you access the ProductList property every time get is called and as a result a new object is created so the object in which you add is lost in the memory somewhere.
Change your class to be :
public class ProductMocks
{
public ProductMocks()
{
ProductList = new List<Products>
{
new Products
{
Id = 1,
Name = "Some Data",
Price = 34.00
},
new Products
{
Id = 2,
Name = "More Data",
Price = 28.00
}
};
}
public IList<Products> ProductList
{
get;
set;
}
}
Now setting the values in constructor that are needed at start, and now you can add as needed on the instance you created in Controller.
or another way would be to have a backing field yourself and check it, if it is null then create instance with default values else return the instance as it is without creating another new one :
public class ProductMocks
{
private IList<Products> _ProductList;
public IList<Products> ProductList
{
get
{
if(_ProductList == null)
{
_ProductList = new List<Products>
{
new Products
{
Id = 1,
Name = "Some Data",
Price = 34.00
},
new Products
{
Id = 2,
Name = "More Data",
Price = 28.00
}
};
}
return _ProductList;
}
}
}
But the second approach might result in unexpected behaviors for the callers, as in cases where they would expect ProductList to be null will have two items in it and not null.
Hope it Helps.

Can't retrieve data from EF database

I have a simple application which should display the elements of a list, but it returns an empty array when debugging. I need this elements to be displayed dinamically. I'm wondering if the program is not working because of the following code...
StoreController.cs
using GetMed.Models;
namespace GetMed.Controllers
{
public class StoreController : Controller
{
GetMedEntities storeDB = new GetMedEntities();
//
// GET: /Store/
public ActionResult Index()
{
var categories = storeDB.Categories.ToList();
return View(categories);
}
}
}
SampleData.cs:
using System.Data.Entity;
namespace GetMed.Models
{
public class SampleData : DropCreateDatabaseIfModelChanges<GetMedEntities>
{
protected override void Seed(GetMedEntities context)
{
var categories = new List<Category>
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
};
}
}
}
GetMedEntities.cs
namespace GetMed.Models
{
public class GetMedEntities : DbContext
{
public DbSet<Category> Categories { get; set; }
}
}
Index.cs:
#model IEnumerable<GetMed.Models.Category>
#{
ViewBag.Title = "Index";
}
<h3>Browse Categories</h3>
<p>Select from #Model.Count() categories:</p>
<ul>
#foreach (var category in Model)
{
<li>#Html.ActionLink(category.Name, "Browse", new { category = category.Name })</li>
}
</ul>
If you look at your database, you will notice that there is no data in it. Look at your Seed method: what do you expect it to do?
After creating your data you have two more steps to do:
Adding it to a collection tracked by your DbContext
Saving it to the database
This results in these extra lines:
context.Categories.AddRange(categories);
context.SaveChanges();
Never initialize EF context gloablly, once it gonna hit you hard, believe me
When adding records to DB via EF you have to call
using (var context = new GetMedEntities)
{
// YOUR ADD ROUTINE GOES HERE
context.SaveChanges();
}
UPDATE
Change your class SampleData
public class SampleData : DropCreateDatabaseIfModelChanges<GetMedEntities>
{
protected override void Seed(GetMedEntities context)
{
//I STRICTLY RECOMMEND NOT TO PROVIDE CONTEXT AS A METHOD PARAMETER
//YOU HAVE TO WRITE PROPER DB LAYER TO DO SO
context.Categories.AddRange( new List<Category>()
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
});
context.SaveChanges();
}
}
But the simple solution is the following:
public class SampleData
{
public void SeedSampleData()
{
var context = new GedMedEntities();
context.Categories.AddRange( new List<Category>()
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
});
context.SaveChanges();

An error occurred when trying to create a controller of type X. Make sure that the controller has a parameterless constructor

I'm working on an asp.net mvc project where I've created a partial view with some dropdowns. These are populated with ajax, and should work as a filter. (Not really relevant to my question, I guess, but nice to know anyhow).
A problem occurrs when trying to invoke the partial view, saying the following:
An error occurred when trying to create a controller of type 'Project.Name.Web.Controllers.PlanFilterController'. Make sure that the controller has a parameterless public constructor.
However, my controller does appear to have a parameterless constructor;
public class PlanFilterController : BaseController
{
public PlanFilterControllerViewModel Model { get; set; }
public List<DropDownItem> Items { get; set; }
public List<ProjectContract> AllProjects { get; set; }
public List<CustomerContract> AllCustomers { get; set; }
public List<UnitContract> AllUnits { get; set; }
private ProjectServiceClient ProjectClient { get; set; }
private CustomerServiceClient CustomerClient { get; set; }
public PlanFilterController()
{
AllProjects = new List<ProjectContract>();
AllCustomers = new List<CustomerContract>();
AllUnits = new List<UnitContract>();
ProjectClient = new ProjectServiceClient();
CustomerClient = new CustomerServiceClient();
AllProjects = ProjectClient.GetProjects().ToList();
AllCustomers = CustomerClient.GetCustomers().ToList();
AllUnits = UnitClient.GetUnits(true, "", false).ToList();
}
// GET: /PlanFilter/
[ChildActionOnly]
public ActionResult FilterControl()
{
return PartialView();
}
// Populate dropdowns
public JsonResult GetCascadeCustomers()
{
Items = new List<DropDownItem>();
foreach (var customer in AllCustomers)
{
Items.Add(new DropDownItem
{
ItemId = customer.Id,
ItemName = customer.Name
});
}
return Json(Items, JsonRequestBehavior.AllowGet);
}
public JsonResult GetCascadeProjects()
{
Items = new List<DropDownItem>();
foreach (var project in AllProjects)
{
Items.Add(new DropDownItem
{
ItemId = project.Id,
ItemName = project.Name
});
}
return Json(Items, JsonRequestBehavior.AllowGet);
}
public JsonResult GetCascadeUnits()
{
Items = new List<DropDownItem>();
foreach (var unit in AllUnits)
{
Items.Add(new DropDownItem
{
ItemId = unit.Id,
ItemName = unit.Name
});
}
return Json(Items, JsonRequestBehavior.AllowGet);
}
}
What am I missing here? Also, if someone could please provide the explanation to why this is the case, that would be nice :)
As mentioned in comments, something had happened when I added my service references, and some code was not automatically generated. This again caused the exception mentioned.

MVC4: View appears to be maintaining state independently of the controller

I have a dropdown (customer) and list of checkboxes (sales orders), dependent upon the currently selected customer. I would expect the checkboxes to clear if I select a new customer, but they are maintained from one to the other, despite the model being cleared in the postback.
I'm not a seasoned MVC developer, but I'm not sure why this should be. When debugging the ViewModel I'm sending back to the view, it is showing IsSelected = false for all the checkboxes, yet in the View, they are selected. What am I doing wrong? (Thanks in advance)
View Model:
namespace MvcTest1.Models
{
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
}
public class SalesOrder
{
public int SalesOrderID { get; set; }
public string Reference { get; set; }
public bool IsSelected { get; set; }
}
public class SalesOrderPageViewModel
{
public List<Customer> Customers { get; set; }
public int SelectedCustomerID { get; set; }
public List<SalesOrder> SalesOrders { get; set; }
}
}
Controller:
namespace MvcTest1.Controllers
{
public class SalesOrderPageController : Controller
{
[HttpGet]
public ActionResult Index()
{
SalesOrderPageViewModel viewModel = BuildViewModel(1);
return View(viewModel);
}
[HttpPost]
public ActionResult Index(SalesOrderPageViewModel viewModelInput)
{
SalesOrderPageViewModel viewModel = BuildViewModel(viewModelInput.SelectedCustomerID);
return View(viewModel);
}
public SalesOrderPageViewModel BuildViewModel(int customerID)
{
SalesOrderPageViewModel viewModel = new SalesOrderPageViewModel
{
Customers = new List<Customer>
{
new Customer { CustomerID = 1, Name = "Alan" },
new Customer { CustomerID = 2, Name = "Bob" },
new Customer { CustomerID = 3, Name = "Charlie" }
}
};
viewModel.SelectedCustomerID = customerID;
if (customerID == 1)
{
viewModel.SalesOrders = new List<SalesOrder>
{
new SalesOrder { SalesOrderID = 11, Reference = "AA11" },
new SalesOrder { SalesOrderID = 12, Reference = "AA22" },
new SalesOrder { SalesOrderID = 13, Reference = "AA33" }
};
}
if (customerID == 2)
{
viewModel.SalesOrders = new List<SalesOrder>
{
new SalesOrder { SalesOrderID = 21, Reference = "BB11" },
new SalesOrder { SalesOrderID = 22, Reference = "BB22" },
new SalesOrder { SalesOrderID = 23, Reference = "BB33" }
};
}
if (customerID == 3)
{
viewModel.SalesOrders = new List<SalesOrder>
{
new SalesOrder { SalesOrderID = 31, Reference = "CC11" },
new SalesOrder { SalesOrderID = 32, Reference = "CC22" },
new SalesOrder { SalesOrderID = 33, Reference = "CC33" }
};
}
return viewModel;
}
}
}
View:
#model MvcTest1.Models.SalesOrderPageViewModel
#{
ViewBag.Title = "SalesOrderPage";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>SalesOrderPage</h2>
<br /><br />
#using (Html.BeginForm())
{
#Html.DropDownListFor(model =>
model.SelectedCustomerID,
new SelectList(
Model.Customers,
"CustomerID",
"Name",
Model.SelectedCustomerID
),
new { id = "customerSelect" }
);
<script type="text/javascript">
$(function () {
$('#customerSelect').change(function () {
this.form.submit();
});
})
</script>
<br /><br />
for (int i = 0; i < Model.SalesOrders.Count(); i++)
{
#Html.DisplayFor(m => Model.SalesOrders[i].Reference)
#Html.CheckBoxFor(m =>
m.SalesOrders[i].IsSelected
)
<br />
}
}
Looks like Ryan is correct about ModelState.Clear(). Here's an article explaining why it is necessary:
http://patrickdesjardins.com/blog/modelstate-clear-is-required-to-display-back-your-model-object

Categories

Resources