DropDownListFor i rzucany wyjątek NullReferenceException

0

Witam,
mam problem z DropDownListFor, wyrzucami mi wyjątek NullReferenceException, próbowałem różnych kombinacji kodu znalieżionych w sieci, ale zawsze jest to samo.

Models:

 public class Category
    {
        [Key]
        [ScaffoldColumn(false)]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int CategoryId { get; set; }

        [Required]
        [Display(Name = "Nazwa kategorii: ")]
        public string Name { get; set; }

        public virtual List<Word> Words { get; set; }

        [ScaffoldColumn(false)]
        public string UserEmail { get; set; }
        public virtual User User { get; set; }
    }

public class User
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [ScaffoldColumn(false)]
        public int UserId { get; set; }

        [Key]
        [Required]
        [EmailAddress]
        [StringLength(100)]
        [Display(Name = "Adres Email: ")]
        public string Email { get; set; }

        [Required]
        [Display(Name = "Hasło: ")]
        public string EncryptedPassword { get; set; }

        [ScaffoldColumn(false)]
        public string PasswordSalt { get; set; }

        [NotMapped]
        public string Password { get; set; }

        public virtual List<Word> Words { get; set; }
        public virtual List<Category> Categorys { get; set; }

    }

 public class Word
    {
        [Key]
        [ScaffoldColumn(false)]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int WordId { get; set; }

        [Required]
        [Display(Name = "Polskie słowo: ")]
        public string PolishWord { get; set; }

        [Required]
        [Display(Name = "Angielskie słowo: ")]
        public string EnglishWord { get; set; }

        [Required]
        public string Status { get; set; }

        [ScaffoldColumn(false)]
        public string UserEmail { get; set; }
        public virtual User User { get; set; }

        public int CategoryId { get; set; }
        public virtual Category Category { get; set; }
    }

public class WordCategory
    {
        public List<Category> category { get; set; }
        public Word word { get; set; }
    }
 

Controller:

 
public ActionResult CreateWord()
        {
            using (var db = new UserContext())
            {
                WordCategory wordCategory = new WordCategory();
                var categorys = db.Categorys.Where(c => c.UserEmail == UserController.ActualyLoggedUser.Email).ToList();
                var newWord = new Word();
                wordCategory.category = categorys;
                wordCategory.word = newWord;
                return View(wordCategory);
            }
        }

View:

 
<div class="form-group">
            @Html.LabelFor(model => model.word.Category, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model=>model.word.CategoryId, new SelectList(Model.category, "CategoryId", "Name")) //w tej linijce wyrzuca wyjątek
                @Html.ValidationMessageFor(model => model.word.Category.Name)
            </div>
        </div>
0

Spróbuj tak:

@Html.DropDownListFor(model=>model.word.CategoryId, Model.category))
 
0

Problem chyba jest w tej pierwszej części czyli w model => model.word.CategoryId, bo lista się wyświetla poprawnie. Zmieniłem klucz obcy w word z CategoryId na CategoryName i zapis z model => model.word.CategoryId na model => model.word.CategoryName, bo gdzieś mi sie rzuciło w oczy że lista zwraca stringa po wybraniu opcji, ale tez nie działa.

0
  1. Czy w tej linijce
  return View(wordCategory);

jak ustawisz breakpoint to wordCategory zawiera tą listę?

  1. Jaki jest model widoku?

  2. Spróbuj w kontrolerze utworzyć listę i przesłać ją VewBagiem - zobacz czy to Ci zadziała.
    Dodaj ten kod do kontrolera przed "return...":

ViewBag.categorys = categorys.Select(x=> new SelectListItem{Text=x.Name, Value=x.Id.ToString()}).ToList();

a tak do widoku zrób ten dropDown:

     @Html.DropDownListFor(model=>model.word.CategoryId, (IEnumerable<SelectList>)ViewBag.categorys) // tu nie jestem pewien czy ma być SelectList czy SelectListItem - spróbuj oba 
0

Tak, jest lista. Model widoku to oczywiscie WordCategory

0

Teraz jest nieco inny problem: There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'CategoryId' (w tej samej linijce co wcześniej)

Aktualnie kod wygląda tak:

public ActionResult CreateWord()
        {
            using (var db = new UserContext())
            {
                var userCategory = db.Categorys.Where(c => c.UserEmail == UserController.ActualyLoggedUser.Email).ToList();
                ViewBag.userCategory = userCategory.Select(x => new SelectListItem { Text = x.Name, Value = x.CategoryId.ToString() }).ToList();

                return View();
            }
        }

@model MasterOfEnglish.Models.Word
@Html.DropDownListFor(model => model.CategoryId, (IEnumerable<SelectListItem>)ViewBag.userCategory)
 
0

Przykładowy obiekt z którego zrobię sobie listę do DropDown-a:

   public class Person
    {
         public string Name { get; set; }
         public int Id { get; set; }
    }

Przykładowy model do zapisania wybranej pozycji w dropDown:

public class MojModel
    {
        public int Id { get; set; }
    }

Akcja kontrolera:
Nie sugeruj się że wybrany mam "Partial1" - nie chciało mi się kasować widoku Contact po prostu :P

   public ActionResult Contact()
        {
            var k = new List<Person> {new Person {Name = "1", Id = 1}, new Person {Name = "2", Id = 2}, new Person {Name = "3", Id = 3}};

            ViewBag.list = k.Select(x => new SelectListItem {Text = x.Name, Value = x.Id.ToString()});

            return View("Partial1");
        }

Kod w widoku:

@model WebApplication3.Controllers.MojModel



@Html.DropDownListFor(model => model.Id, (IEnumerable<SelectListItem>)ViewBag.list)

W załączniku screen ;)

0

Przeczytałem Twój kod jeszcze raz!
w tej części:

ViewBag.userCategory = userCategory.Select(x => new SelectListItem { Text = x.Name, Value = x.CategoryId.ToString() }).ToList();

usuń to "ToList();"

0

Moj kod jest zrobiony dokładnie wg schematu, który podałeś, bez ToList() też próbowałem, ale cały czas jest to samo. Wiele rozwiązań już próbowałem znaleźionych w sieci niestety nic nie działa.

0

Są, bo lista rozwijana normalnie się tworzy, dopiero jak naciskam w przycisk zatwierdzający wpisane dane w przeglądarce, wyskakuje ten błąd. Po prostu nie może zapisac wybranego z listy elementu do model.CategoryId bo mu sie typ nie zgadza tylko nie rozumiem dlaczego

0

No to pokaż jaką masz akcję kontrolera która ma przyjąć dane z tego widoku.

0

Co znajduję się pod tym obiektem w debugerze?

 var newWord = new Word(); 

bo w tej linijce

wordCategory.word = newWord; 

przypisujesz pustą referencje do obiektu
pokaż wynik z debugera.

0
        [HttpPost]
        public ActionResult CreateWord(Models.Word word)
        {
            if (ModelState.IsValid)
            {

                using (var db = new UserContext())
                {
                    var newWord = db.Words.Create();
                    newWord.PolishWord = word.PolishWord;
                    newWord.EnglishWord = word.EnglishWord;
                    newWord.Status = "nieznane";
                    newWord.CategoryId = word.CategoryId;
                    newWord.UserEmail = UserController.ActualyLoggedUser.Email;

                    db.Words.Add(newWord);
                    db.SaveChanges();

                }
                return RedirectToAction("CreateWord", "UserAccount");
            }
            else
            {
                ModelState.AddModelError("", "Podane dane są nieprawidłowe!");
            }

            return View(word);
        } 

@Rejencina teraz używam ViewBag do przesłania listy wiec z tego o co pytasz nie korzystam, teraz kod metody HttpGet wyglada tak:

[HttpGet]
        public ActionResult CreateWord()
        {
            using (var db = new UserContext())
            {
                var userCategory = db.Categorys.Where(c => c.UserEmail == UserController.ActualyLoggedUser.Email).ToList();
                ViewBag.userCategory = userCategory.Select(x => new SelectListItem { Text = x.Name, Value = x.CategoryId.ToString() });

                return View();
            }
        }
 
0

Obstawiam, że strona Ci sie po prostu nie validuje i uruchamia się ponownie, ale z nullem zamiast listy z ViewBag. Dodaj ten kod do metody post w else'ie.

using (var db = new UserContext())
            {
                var userCategory = db.Categorys.Where(c => c.UserEmail == UserController.ActualyLoggedUser.Email).ToList();
                ViewBag.userCategory = userCategory.Select(x => new SelectListItem { Text = x.Name, Value = x.CategoryId.ToString() });
 
                return View();
            } 
0

Dzięki, błąd już się nie pojawia a jedynie powiadomienie z elsa, że błędne dane. Pytanie tylko dlaczego , nie mam żadnych ograniczeń narzuconych na dane więc w sumie cokolwiek tam wpisze powinno działać.

0

Jeśli ten widok który wrzuciłeś to całość i nie ma w nim żadnego innego kodu to PRAWDOPODOBNIE dzieję się tak że Ty wypełniasz tylko 1 pole w modelu, no a reszta jest null -> ale nie jestem pewien co do tego.

Możesz spróbować w widoku na sztywne ustawić resztę właściwości z tego modelu.

0

W metodzie post wpisujesz wartość właściwości status na sztywno

newWord.Status = "nieznane"; 

więc zakładam, że w widoku nie pobierasz wartości dla tej właściwości od użytkownika. Natomiast w modelu masz tą właściwośc ustawioną na Required [Required]
public string Status { get; set; }

więc jeżeli nie przypiszesz jej nic w widoku to sie nie zwaliduje.

Najlepiej podaj cały kod widoku i będzie łatwiej coś wymyślić.
0

Po usunięciu Required z modelu wszystko działa poprawnie, bardzo dziękuję wszystkim za pomoc :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1