J'essaie d'apprendre MVC et je suis le didacticiel de l'Université Contoso situé ici

J'ai construit avec succès un projet qui a une base de données avec les étudiants, les cours et les inscriptions. Actuellement j'ai 3 modèles,

  1. Cours
  2. Inscription
  3. Étudiante

Et 2 contrôleurs

  1. HomeController
  2. StudentController

Actuellement, mon routage est le routage par défaut que vous obtenez avec un projet MVC.

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

Et cela fonctionne bien pour saisir les détails des étudiants en fonction de StudentID

Donc l'URL

http://localhost:49706/Student/Details/1

Renvoie ceci Détails de l'étudiant

Cela fonctionne très bien, mais j'essaie de comprendre le routage un peu plus en profondeur. Je souhaite créer une nouvelle vue qui affichera les détails de l'élève en fonction de LAST NAME plutôt que de la carte d'étudiant. Oui, je sais que dans le monde réel, ce ne serait pas une bonne idée car les noms de famille ne sont pas uniques, mais c'est bien pour cette démonstration car ma base de données ne s'agrandira pas et je sais que tous les noms de famille sont actuellement uniques.

La première chose que j'ai faite a été de créer un nouveau résultat d'action dans mon StudentController

public ActionResult Grab(string studentName)
{
    if(studentName == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Student student = db.Students.Find(studentName);
    if(student == null)
    {
        return HttpNotFound();
    }
    return View(student);
}

La deuxième chose que j'ai faite a été de cliquer avec le bouton droit sur «Grab» et d'ajouter une vue. J'ai appelé le nom de la vue «Grab». Définissez le modèle comme «Liste». Définissez la classe de modèle sur «Student (ContosoUniversity.Models)». et DataContextClass à «SchoolContext (ContosoUniversity.DAL)».

Add View

Quand j'appelle ça http: // localhost: 49706 / Student / Grab

J'obtiens une erreur 400 comme je l'ai écrit dans le contrôleur. Cependant, lorsque j'essaye l'url suivante

http://localhost:49706/Student/Grab/Alexander

J'obtiens également une autre erreur 400. Je ne sais pas vraiment ce que j'ai laissé de côté. Puis-je obtenir de l'aide s'il vous plaît.

Voici à quoi ressemble ma base de données

Database

Encore une fois, tout ce que je veux faire est de pouvoir saisir l'url suivante http: // localhost: 49706 / Student / Grab / {LastName}

Et demandez-lui d'afficher les détails de l'élève avec le nom de famille correspondant.

Merci pour votre temps

ÉDITER

Mise à jour de ActionResult Grab

public ActionResult Grab(string studentName)
{
    if(studentName == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Student student = db.Students.Where(student => student.LastName.Contains(studentName)).FirstOrDefault();
    if (student == null)
    {
        return HttpNotFound();
    }
    return View(student);
}

Contrôleur étudiant entier

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using ContosoUniversity.DAL;
using ContosoUniversity.Models;

namespace ContosoUniversity.Controllers
{
    public class StudentController : Controller
    {
        private SchoolContext db = new SchoolContext();

        // GET: Student
        public ActionResult Index()
        {
            return View(db.Students.ToList());
        }

        // GET: Student/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = db.Students.Find(id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        public ActionResult Grab(string studentName)
        {
            if(studentName == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = db.Students.Where(student => student.LastName.Contains(studentName)).FirstOrDefault();
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // GET: Student/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Student/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 ActionResult Create([Bind(Include = "LastName, FirstMidName, EnrollmentDate")]Student student)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    db.Students.Add(student);
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            }
            catch (DataException /* dex */)
            {
                //Log the error (uncomment dex variable name and add a line here to write a log.
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
            }
            return View(student);
        }

        // GET: Student/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = db.Students.Find(id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // POST: Student/Edit/5
        // 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, ActionName("Edit")]
        [ValidateAntiForgeryToken]
        public ActionResult EditPost(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var studentToUpdate = db.Students.Find(id);
            if (TryUpdateModel(studentToUpdate, "",
               new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
            {
                try
                {
                    db.SaveChanges();

                    return RedirectToAction("Index");
                }
                catch (DataException /* dex */)
                {
                    //Log the error (uncomment dex variable name and add a line here to write a log.
                    ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
                }
            }
            return View(studentToUpdate);
        }

        // GET: Student/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Student student = db.Students.Find(id);
            if (student == null)
            {
                return HttpNotFound();
            }
            return View(student);
        }

        // POST: Student/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Student student = db.Students.Find(id);
            db.Students.Remove(student);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

Grâce aux suggestions jusqu'à présent, j'ai maintenant une page qui revient. Cependant, aucune donnée n'est chargée. Voici une photo Presque fonctionnel

Voici le code de la vue

@model ContosoUniversity.Models.Student

    @{
        ViewBag.Title = "Grab";
    }

    <h2>Grab</h2>

    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.LastName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.FirstMidName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </th>
            <th></th>
        </tr>

    </table>
1
onTheInternet 20 avril 2017 à 19:47

3 réponses

Meilleure réponse

Votre problème est le routage. Lorsque vous demandez http://localhost:49706/Student/Grab/{LastName}, le paramètre studentName se résout en null, d'où votre BadRequestResponse.

Le modèle dans votre URL correspond au modèle d'itinéraire ASP.NET MVC par défaut, mais il ne parviendra pas à lier la valeur du paramètre, donc MVC atteindra correctement votre contrôleur et votre action, mais le paramètre sera nul.

Vous avez plusieurs options:

Cartographier un itinéraire

Vous pouvez l'ajouter à votre fichier de configuration de routage: RouteConfig.cs dans le répertoire App_Start:

//Add your own route
routes.MapRoute(
    name: null,
    url: "{controller}/{action}/{studentName}",
    defaults: new { controller = "Student", action = "Grab", id = UrlParameter.Optional }
);

Cet appel doit précéder l'appel pour mapper l'itinéraire par défaut. Vous pourrez maintenant obtenir la valeur du paramètre studentName à partir des données d'itinéraire.

Changer l'URL

Vous pouvez appeler la même action sans ajouter de nouvel itinéraire en demandant votre page en tant que:

http://localhost:49706/Student/Grab?studentName={LastName}

Ici, le paramètre sera traité efficacement.

En ce qui concerne la récupération de l'élève dans la base de données, j'utiliserais ce code dans l'action si je veux simplement faire correspondre le nom de famille complet:

public ActionResult Grab(string studentName)
{
    if (studentName == null)
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);

    var student = db.Students.FirstOrDefault(x => x.LastName.ToLower() == studentName.ToLower());
    if (student == null)
        return HttpNotFound();

    return View(student);
}

Faites moi savoir comment ça marche pour vous.

J'espère que cela t'aides!

2
Karel Tamayo 20 avril 2017 à 18:21

Je suppose que vous essayez cela à partir de la vue Index .. donc puisque votre Grab ActionResult attend un paramètre appelé studentName (vous voudrez peut-être renommer quelque chose qui correspond à lastName pour des raisons de maintenabilité ) .. un lien d'action sur votre vue Index doit ressembler à ceci:

@Html.ActionLink("Details by Last Name", "Grab", "Student", new{studentName = item.LastName}, null)
// I assume `item` because if it's in your Index view you are looping to get each user in their own row..

Puisque vous comprenez qu'utiliser le nom de famille d'une personne est une mauvaise idée car il n'est pas unique ... mais dans ce cas, il l'est .. il n'est pas nécessaire d'utiliser la méthode .Contain() .. Vous recherchez UNE personne, vous devez donc utiliser .SingleOrDefault().

public ActionResult Grab(string studentName)
{
    // in my experience.. when you're checking a string variable to see if 
    // it is null.. use string.IsNullOrWhiteSpace.. because even though what
    // you're using checks for null.. it doesn't check for white space..


    if(studentName == null) // so change this to if(string.IsNullOrWhiteSpace(studentName))
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);

    Student student = db.Students.SingleOrDefault(student => student.LastName.ToLower() == studentName.ToLower()); // convert the comparison strings to all lower case.. hence the the `.ToLower()` methods for more reliable comparison

    if (student == null)
        return HttpNotFound();

    return View(student);
}

J'espère que cela t'aides.

0
Grizzly 20 avril 2017 à 19:07

Votre première erreur:

db.Students.Find(studentName); // This one expects an student object not string

Vous devez donc utiliser l'extension linq Where pour pouvoir filtrer votre table des élèves par nom de famille comme ceci:

Student student = db.Students.Where(student => student.LastName.Contains(studentName)).FirstOrDefault(); // Im using contains instead of equals to match substrings

0
Sherlock 20 avril 2017 à 17:29