it-swarm.com.de

Trennen des Datenzugriffs in ASP.NET MVC

Ich möchte sicherstellen, dass ich bei meinem ersten echten Crack bei MVC den Industriestandards und Best Practices folge. In diesem Fall handelt es sich um ASP.NET MVC mit C #.

Ich werde Entity Framework 4.1 für mein Modell mit Code-First-Objekten verwenden (die Datenbank ist bereits vorhanden), sodass es ein DBContext-Objekt zum Abrufen von Daten aus der Datenbank gibt.

In den Demos, die ich auf der asp.net-Website durchgesehen habe, enthalten Controller Datenzugriffscode. Dies scheint mir nicht richtig zu sein, insbesondere wenn ich die Praktiken von DRY (wiederhole dich nicht)) befolge.

Angenommen, ich schreibe eine Webanwendung zur Verwendung in einer öffentlichen Bibliothek und habe einen Controller zum Erstellen, Aktualisieren und Löschen von Büchern in einem Katalog.

Einige der Aktionen benötigen möglicherweise eine ISBN und müssen ein "Buch" -Objekt zurückgeben (beachten Sie, dass dies wahrscheinlich kein 100% gültiger Code ist):

public class BookController : Controller
{
    LibraryDBContext _db = new LibraryDBContext();

    public ActionResult Details(String ISBNtoGet)
    {
        Book currentBook = _db.Books.Single(b => b.ISBN == ISBNtoGet);
        return View(currentBook);
    }

    public ActionResult Edit(String ISBNtoGet)
    {
        Book currentBook = _db.Books.Single(b => b.ISBN == ISBNtoGet);
        return View(currentBook);
    }
}

Stattdessen sollte Ich habe tatsächlich eine Methode in meinem Datenbankkontextobjekt, um ein Buch zurückzugeben? Das scheint mir eine bessere Trennung zu sein und hilft bei der Förderung von DRY, da ich möglicherweise ein Buchobjekt von ISBN an einer anderen Stelle in meiner Webanwendung abrufen muss.

public partial class LibraryDBContext: DBContext
{
    public Book GetBookByISBN(String ISBNtoGet)
    {
        return Books.Single(b => b.ISBN == ISBNtoGet);
    }
}

public class BookController : Controller
{
    LibraryDBContext _db = new LibraryDBContext();

    public ActionResult Details(String ISBNtoGet)
    {
        return View(_db.GetBookByISBN(ISBNtoGet));
    }

    public ActionResult Edit(ByVal ISBNtoGet as String)
    {
        return View(_db.GetBookByISBN(ISBNtoGet));
    }
}

Ist dies ein gültiger Satz von Regeln, die bei der Codierung meiner Anwendung zu beachten sind?

Oder ich denke, eine subjektivere Frage wäre: "Ist das der richtige Weg, dies zu tun?"

35
scott.korin

Im Allgemeinen möchten Sie, dass Ihre Controller nur einige Dinge tun:

  1. Behandeln Sie die eingehende Anfrage
  2. Delegieren Sie die Verarbeitung an ein Geschäftsobjekt
  3. Übergeben Sie das Ergebnis der Geschäftsverarbeitung an die entsprechende Ansicht zum Rendern

Es sollte keinen Datenzugriff oder keine komplexe Geschäftslogik in der Steuerung geben.

[In den einfachsten Apps können Sie wahrscheinlich mit CRUD-Aktionen für grundlegende Daten in Ihrem Controller durchkommen. Wenn Sie jedoch mehr als nur einfache Get- und Update-Aufrufe hinzufügen, möchten Sie Ihre Verarbeitung in eine separate Klasse aufteilen. ]]

Ihre Controller sind normalerweise auf einen "Service" angewiesen, um die eigentliche Verarbeitungsarbeit zu erledigen. In Ihrer Serviceklasse können Sie direkt mit Ihrer Datenquelle (in Ihrem Fall dem DbContext) arbeiten, aber noch einmal, wenn Sie feststellen, dass Sie viel schreiben Zusätzlich zum Datenzugriff möchten Sie wahrscheinlich Ihre Geschäftslogik von Ihrem Datenzugriff trennen.

Zu diesem Zeitpunkt haben Sie wahrscheinlich eine Klasse, die nur den Datenzugriff ausführt. Manchmal wird dies als Repository bezeichnet, aber es spielt keine Rolle, wie der Name lautet. Der Punkt ist, dass sich der gesamte Code zum Abrufen von Daten in und aus der Datenbank an einem Ort befindet.

Für jedes MVC-Projekt, an dem ich gearbeitet habe, hatte ich immer eine Struktur wie:

Controller

public class BookController : Controller
{
    ILibraryService _libraryService;

    public BookController(ILibraryService libraryService)
    {
        _libraryService = libraryService;
    }

    public ActionResult Details(String isbn)
    {
        Book currentBook = _libraryService.RetrieveBookByISBN(isbn);
        return View(ConvertToBookViewModel(currentBook));
    }

    public ActionResult DoSomethingComplexWithBook(ComplexBookActionRequest request)
    {
        var responseViewModel = _libraryService.ProcessTheComplexStuff(request);
        return View(responseViewModel);
    }
}

Business Service

public class LibraryService : ILibraryService
{
     IBookRepository _bookRepository;
     ICustomerRepository _customerRepository;

     public LibraryService(IBookRepository bookRepository, 
                           ICustomerRepository _customerRepository )
     {
          _bookRepository = bookRepository;
          _customerRepository = customerRepository;
     }

     public Book RetrieveBookByISBN(string isbn)
     {
          return _bookRepository.GetBookByISBN(isbn);
     }

     public ComplexBookActionResult ProcessTheComplexStuff(ComplexBookActionRequest request)
     {
          // Possibly some business logic here

          Book book = _bookRepository.GetBookByISBN(request.Isbn);
          Customer customer = _customerRepository.GetCustomerById(request.CustomerId);

          // Probably more business logic here

          _libraryRepository.Save(book);

          return complexBusinessActionResult;

     } 
}

Repository

public class BookRepository : IBookRepository
{
     LibraryDBContext _db = new LibraryDBContext();

     public Book GetBookByIsbn(string isbn)
     {
         return _db.Books.Single(b => b.ISBN == isbn);
     }

     // And the rest of the data access
}
55
Eric King

So habe ich es gemacht, obwohl ich den Datenprovider als generische Datendienstschnittstelle einspeise, damit ich Implementierungen austauschen kann.

Soweit ich weiß, soll der Controller der Ort sein, an dem Sie Daten abrufen, Aktionen ausführen und Daten an die Ansicht übergeben.

2
Nathan Craddock