Master detail mvc .net core

0

Cześć!

Chcę zrobić CRUD w mvc .net core 2.2. Stworzyłem model klientów oraz umów. W widoku szczegółów klienta umieściłem przycisk pokazujący umowy klienta. Wygląda to mniej więcej tak na widoku szczegółów klienta:

 <a asp-controller="Contracts" asp-action="Index" asp-route-custommerID="@Model.ID">Pokaż umowy</a>

Czyli przekazuję do kontrolera ID klienta. Obsługa tego wygląda tak:

        // GET: Contracts
        public IActionResult Index(int custommerID)
        {
            ViewData["CustommerID"] = custommerID;
            return View(_contracts.GetContracts().Where(x => x.CustommerID == custommerID));
        }

Na widoku umów mam klasyczną tabelkę w html i możliwość dodania umowy poprzez:

<a asp-action="Create" asp-route-custommerID="@ViewData["CustommerID"]">Create New</a>

Jak widać, przekazałem ID klienta do widoku i dalej do kontrolera poprzez @ViewData

Obsługa nowej umowy wygląda tak:

        // GET: Contracts/Create
        public IActionResult Create(int? custommerID)
        {
            CustomerContract customerContract = new CustomerContract();
            customerContract.CustomerId = custommerID.GetValueOrDefault();
            return View(customerContract);
        }

Tworzę nowy ViewModel i przypisuje mu ID klienta. Poniżej jego definicja:

public class CustomerContract
    {
        public int CustomerId
        {
            get
            {
                return CusContract.CustommerID;
            }

            set
            {
                CusContract.CustommerID = value;
            }
        }
        public Contract CusContract { get; set; }

        public CustomerContract()
        {
            CusContract = new Contract();
        }
    }

Widok edycji wygląda tak:

@model ProjectTestCRUD.ViewModels.CustomerContract

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Contract</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="CusContract.Symbol" class="control-label"></label>
                <input asp-for="CusContract.Symbol" class="form-control" />
                <span asp-validation-for="CusContract.Symbol" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="CusContract.Description" class="control-label"></label>
                <input asp-for="CusContract.Description" class="form-control" />
                <span asp-validation-for="CusContract.Description" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="CusContract.FromDate" class="control-label"></label>
                <input asp-for="CusContract.FromDate" class="form-control" />
                <span asp-validation-for="CusContract.FromDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="CusContract.ToDate" class="control-label"></label>
                <input asp-for="CusContract.ToDate" class="form-control" />
                <span asp-validation-for="CusContract.ToDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="CusContract.Price" class="control-label"></label>
                <input asp-for="CusContract.Price" class="form-control" />
                <span asp-validation-for="CusContract.Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

Obsługa posta przy tworzeniu wygląda tak:

        // POST: Contracts/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Create(CustomerContract customerContract)
        {
            if (ModelState.IsValid)
            {
                _contracts.AddContract(customerContract.CusContract);
                return RedirectToAction(nameof(Index), new { custommerID = customerContract.CustomerId });
            }
            return View(customerContract);
        }

Problem jest taki, że mimo, że do widoku przekazuję utworzony ViewModel CustomerContract, tak z widoku do obsługi Post Create leci już zupełnie nowy obiekt uzupełniony poprzez widok. W jaki sposób przekazywać do widoku create ID klienta, żeby kontroler wiedział jakiemu klientowi założyć umowę? Udało mi się to zrobić, poprzez ukryty input z ID klienta, ale wydaje mi się to mało profesjonalne i bezpieczne. Z góry dzięki za sugestie.

1

Nie możesz utworzyć sobie ścieżki customers/{customerId}/contracts/create? Wtedy przekazałbyś to ID klienta za pomocą asp-route-customerid I ten ViewModel mógłbyś też sobie poprawić:

public class AddCustomerContractViewModel
    {
        public int CustomerId { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        // ...
    }

W widoku przydałoby się też jakoś poinformować użytkownika, dla którego klienta ten kontrakt jest tworzony, bo ID w ścieżce albo w ukrytym inpucie to raczej za mało :P Więc pewnie warto byłoby dać też do widoku jakieś CustomerFullName.

0

Ale tak się serio robi? Nie mogę znaleźć w sieci żadnego sensownego przypadku. No i gdzie to obsłużyć - w kontrolerze umowy? Ofc. ViewModel jest do poprawki - dzięki za uwagę.

1
electron napisał(a):

Udało mi się to zrobić, poprzez ukryty input z ID klienta, ale wydaje mi się to mało profesjonalne i bezpieczne.

To jest typowe rozwiązanie dla takich problemów. To aplikacja po stronie serwera musi sprawdzić poprawność danych. W Twoim przypadku to aplikacja musi sprawdzić czy ukryte id użytkownika przesłane w formularzu jest takie samo jako id użytkownika zalogowanego.

0

Dzięki za pomoc. Zasięgnąłem opinii i faktycznie sporo osób używa ukrytych inputów do przekazywania do formularza stałych jak np. ID rodzica danej encji. Niemniej zamiast klasycznego inputa użyłem:

@Html.HiddenFor(cc => cc.CustomerId); 

który dodałem do formularza. Wydaje mi, się, że warto używać do takich rzeczy Razora. Dzięki za opinię i pomoc. Sam ViewModel też rozbudowałem.

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