MVC Strongly-typed object view->controller

0

Witam,
Jestem w trakcie nauki asp.net MVC5, postanowiłem stworzyć prostą stronę, lecz..
Mam problem z przekazaniem silnie typowanego obiektu z widoku do kontrolera.
Mój kod:

Model:

namespace MvcKursVS13.Models
{
    public class Film
    {
        public Film()
        {
            Recenzje = new List<Recenzja>();
        }

        public int FilmId { get; set; }

        [Display(Name = "Tytuł (PL)")]
        public string TytulPl { get; set; }

        [Display(Name = "Tytuł (EN)")]
        public string TytulEn { get; set; }

        [Display(Name = "Data premiery (Polska)")]
        public DateTime DataPremieryPl { get; set; }

        [Display(Name = "Data premiery (Świat)")]
        public DateTime DataPremierySwiat { get; set; }

        [Display(Name = "Gatunek")]
        public string Gatunek { get; set; }

        [Display(Name = "Reżyser")]
        public string Rezyser { get; set; }

        virtual public ICollection<Recenzja> Recenzje { get; set; }

        
    }
}

Controller:

public async Task<ActionResult> Reviews(int id)
        {
            var film = await db.Filmy.FindAsync(id);
            return View(film);
        }

        [HttpPost]
        public async Task<ActionResult> Reviews(Film filmEntity)//, string textboxik)
        {
            var movie = await db.Filmy.FindAsync(filmEntity.FilmId);
           // movie.Recenzje.Add(new Recenzja { DataNapisania = DateTime.Now, WlasciwaRecenzja = textboxik, Autor = User.Identity.Name });

            await db.SaveChangesAsync();
            ModelState.Clear();

            return View(movie);

        }

View:

@model MvcKursVS13.Models.Film

    @{
        ViewBag.Title = "Film" + Model.TytulPl;
      //  Layout = "_Layout.cs";
    }

    <h2>title</h2>

    <tr>Wprowadź własną recenzję:</tr>

@using (Html.BeginForm())
    {
 //   <input type="text" name="textboxik" style="width:550px;height:100px;" />
     <input type="submit" value="Dodaj!" />
    }

Nie jest to pełny kod, męczę się z tym już od jakiegoś czasu, więc pousuwałem niepotrzebne rzeczy.

Co jest problemem?

W pierwszym kontrolerze public async Task<ActionResult> Reviews(int id) __poprawnie __pobiera z bazy danych obiekt Film o danym id. Następnie __poprawnie __przekazuje go do widoku. Problem zaczyna się przy drugim kontrolerze ( public async Task<ActionResult> Reviews(Film filmEntity) - obiekt Film przekazany do niego jest zawsze nullem. Nie mam pojęcia dlaczego tak się dzieje - powinien przecież zostać przypisany obiekt silnie typowany z widoku.

Czy spotkał się ktoś może z czymś takim i wie co powinienem w tej sytuacji zrobić?

Z góry wielkie dzięki za odpowiedzi,
M.

1

Ekspertem nie jestem, ale ja bym nie tworzyl obiektu nie majac z czego go stworzyc.

Wrzuc przed submit @Html.EditorForModel() i wyslij i sprawdz czy sie tworzy.

Poza tym:
#Protip: uzywaj narzedzi developerskich wbudowanych w wiekszosci przegladarek, debuggerow http i wstawiaj wiecej informacji na przyszlosc.

Edit:

Zrobilem maly test, dla kodu:

namespace Test.Models {
    public class SimpleModel {
        public SimpleModel() {
            Ints = new List<int>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName { get; set; }
        public virtual ICollection<int> Ints { get; set; }
    }
}

namespace Test.Controllers {
    public class TestController : Controller {
        [HttpGet]
        public ActionResult Something() {
            return View();
        }

        [HttpPost]
        public ActionResult Something(SimpleModel model) {
            if (model != null) return View("DisplayModel", model);

            return View();
        }
    }
}

// Something.cshtml
@model Test.Models.SimpleModel

@using(Html.BeginForm()) {
    @Html.EditorForModel()
    <input type="submit" value="Click!"/>
}

// DisplayModel.cshtml
@model Test.Models.SimpleModel

<span>@Model.Id</span>
<span>@Model.Name</span>
<span>@Model.LastName</span>

Wszystko dziala.

0

Faktycznie masz rację, po dodaniu @html.EditorForModel() i wypełnieniu przekazany obiekt nie jest nullem.

Przedtem (błędnie) myślałem, że obiekt przechodzi tak: kontroler -> widok -> kontroler, a używając jakichś EditorFor'ów tylko zmieniamy poszczególne pola tego obiektu. A tutaj okazuje się, że tworzy się nowy obiekt.

Z tego wynika, że aby przekazać obiekt z pierwszego kontrolera do widoku, ale też do drugiego kontrolera, trzeba by użyć @html.HiddenFor na kazdym jego polu.

Tak czy siak, wielkie dzięki n0name_l za uświadomienie mnie :)

Pozdrawiam,
M.

1
Mikey napisał(a):

Przedtem (błędnie) myślałem, że obiekt przechodzi tak: kontroler -> widok -> kontroler, a używając jakichś EditorFor'ów tylko zmieniamy poszczególne pola tego obiektu. A tutaj okazuje się, że tworzy się nowy obiekt.

Obiekt to coś, co siedzi w pamięci. Kontroler pracuje na serwerze. Widok zaś jest wyświetlany w przeglądarce, która może być oddalona od serwera o tysiące kilometrów. Jak chciałbyś trzymać referencje do obiektu na taką odległość? ;)

Między widokiem a kontrolerem znajduje się pewna magiczna cześć - model binder. On parsuje żądanie HTTP przysłane przez przeglądarkę i buduje z niego obiekt modelu przypisując poszczególnym właściwościom obiektu, odpowiadające wartości żądania. W najprostszej wersji łączy jest wg wartości atrybutu name danego inputa.

Z tego wynika, że aby przekazać obiekt z pierwszego kontrolera do widoku, ale też do drugiego kontrolera, trzeba by użyć @html.HiddenFor na kazdym jego polu.

Niekoniecznie. Wystarczy przesłać jakiś jego identyfikator, a następnie odczytać ten obiekt z bazy danych czy jakiegoś innego cache.

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