Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
von Rick Anderson
Abgeschlossenes Projekt herunterladen
Hinzufügen eines Produktcontrollers
Der Administratorcontroller richtet sich an Benutzer mit Administratorrechten. Kunden können dagegen Produkte anzeigen, aber sie nicht erstellen, aktualisieren oder löschen.
Der Zugriff auf die Methoden "Post", "Put" und "Delete" kann problemlos eingeschränkt werden, während die Get-Methoden geöffnet bleiben. Sehen Sie sich aber die Daten an, die für ein Produkt zurückgegeben werden:
{"Id":1,"Name":"Tomato Soup","Price":1.39,"ActualCost":0.99}
Die ActualCost Eigenschaft sollte für Kunden nicht sichtbar sein! Die Lösung besteht darin, ein DTO (Data Transfer Object ) zu definieren, das eine Teilmenge von Eigenschaften enthält, die für Kunden sichtbar sein sollten. Wir verwenden LINQ, um die Product-Instanzen in die ProductDTO-Instanzen zu projizieren.
Fügen Sie dem Ordner "Models" eine Klasse hinzu, die benannt ist ProductDTO .
namespace ProductStore.Models
{
public class ProductDTO
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Fügen Sie nun den Controller hinzu. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner "Controller". Wählen Sie "Hinzufügen" und dann "Controller" aus. Nennen Sie im Dialogfeld " Controller hinzufügen " den Controller "ProductsController". Wählen Sie unter "Vorlage" den Leeren API-Controller aus.
Ersetzen Sie alles in der Quelldatei durch den folgenden Code:
namespace ProductStore.Controllers
{
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using ProductStore.Models;
public class ProductsController : ApiController
{
private OrdersContext db = new OrdersContext();
// Project products to product DTOs.
private IQueryable<ProductDTO> MapProducts()
{
return from p in db.Products select new ProductDTO()
{ Id = p.Id, Name = p.Name, Price = p.Price };
}
public IEnumerable<ProductDTO> GetProducts()
{
return MapProducts().AsEnumerable();
}
public ProductDTO GetProduct(int id)
{
var product = (from p in MapProducts()
where p.Id == 1
select p).FirstOrDefault();
if (product == null)
{
throw new HttpResponseException(
Request.CreateResponse(HttpStatusCode.NotFound));
}
return product;
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
Der Controller verwendet weiterhin die OrdersContext, um die Datenbank abzufragen. Statt Product-Instanzen direkt zurückzugeben, rufen wir MapProducts auf, um sie auf ProductDTO-Instanzen zu projizieren.
return from p in db.Products select new ProductDTO()
{ Id = p.Id, Name = p.Name, Price = p.Price };
Die MapProducts Methode gibt eine IQueryable zurück, sodass wir das Ergebnis mit anderen Abfrageparametern verfassen können. Sie können dies in der GetProduct Methode sehen, die der Abfrage eine Where-Klausel hinzufügt:
var product = (from p in MapProducts()
where p.Id == 1
select p).FirstOrDefault();
Hinzufügen eines Auftragscontrollers
Fügen Sie als Nächstes einen Controller hinzu, mit dem Benutzer Bestellungen erstellen und anzeigen können.
Wir beginnen mit einem anderen DTO. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner "Modelle", und fügen Sie eine Klasse mit dem Namen OrderDTO hinzu. Verwenden Sie die folgende Implementierung:
namespace ProductStore.Models
{
using System.Collections.Generic;
public class OrderDTO
{
public class Detail
{
public int ProductID { get; set; }
public string Product { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
public IEnumerable<Detail> Details { get; set; }
}
}
Fügen Sie nun den Controller hinzu. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner "Controller". Wählen Sie "Hinzufügen" und dann "Controller" aus. Legen Sie im Dialogfeld " Controller hinzufügen " die folgenden Optionen fest:
- Geben Sie unter "Controllername" "OrdersController" ein.
- Wählen Sie unter "Vorlage" die Option "API-Controller mit Lese-/Schreibaktionen mithilfe von Entity Framework" aus.
- Wählen Sie unter "Model"-Klasse "Order (ProductStore.Models)" aus.
- Wählen Sie unter "Data context class" die Option "OrdersContext (ProductStore.Models)" aus.
Klicken Sie auf Hinzufügen. Dadurch wird eine Datei mit dem Namen OrdersController.cs hinzugefügt. Als Nächstes müssen wir die Standardimplementierung des Controllers ändern.
Löschen Sie zunächst die PutOrder Und DeleteOrder Methoden. Für dieses Beispiel können Kunden vorhandene Bestellungen nicht ändern oder löschen. In einer echten Anwendung benötigen Sie viele Back-End-Logik, um diese Fälle zu behandeln. (Wurde z. B. die Bestellung bereits ausgeliefert?)
Ändern Sie die GetOrders Methode, um nur die Bestellungen zurückzugeben, die dem Benutzer angehören:
public IEnumerable<Order> GetOrders()
{
return db.Orders.Where(o => o.Customer == User.Identity.Name);
}
Ändern Sie die GetOrder Methode wie folgt:
public OrderDTO GetOrder(int id)
{
Order order = db.Orders.Include("OrderDetails.Product")
.First(o => o.Id == id && o.Customer == User.Identity.Name);
if (order == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return new OrderDTO()
{
Details = from d in order.OrderDetails
select new OrderDTO.Detail()
{
ProductID = d.Product.Id,
Product = d.Product.Name,
Price = d.Product.Price,
Quantity = d.Quantity
}
};
}
Hier sind die Änderungen, die wir an der Methode vorgenommen haben:
- Der Rückgabewert ist eine
OrderDTOInstanz anstelle einesOrder. - Wenn wir die Datenbank für die Reihenfolge abfragen, verwenden wir die DbQuery.Include-Methode , um die zugehörigen
OrderDetailundProductEntitäten abzurufen. - Wir vereinfachen das Ergebnis mithilfe einer Projektion.
Die HTTP-Antwort enthält ein Array von Produkten mit Mengen:
{"Details":[{"ProductID":1,"Product":"Tomato Soup","Price":1.39,"Quantity":2},
{"ProductID":3,"Product":"Yo yo","Price":6.99,"Quantity":1}]}
Dieses Format ist für Clients einfacher zu verwenden als das ursprüngliche Objektdiagramm, das geschachtelte Entitäten (Reihenfolge, Details und Produkte) enthält.
Die letzte Methode zu berücksichtigen ist PostOrder. Diese Methode verwendet derzeit eine Order Instanz. Überlegen Sie aber, was passiert, wenn ein Client einen Anforderungstext wie folgt sendet:
{"Customer":"Alice","OrderDetails":[{"Quantity":1,"Product":{"Name":"Koala bears",
"Price":5,"ActualCost":1}}]}
Dies ist eine gut strukturierte Reihenfolge, und Entity Framework fügt sie glücklich in die Datenbank ein. Sie enthält jedoch eine Produktentität, die zuvor nicht vorhanden war. Der Kunde hat soeben ein neues Produkt in unserer Datenbank erstellt! Dies wird eine Überraschung für die Auftragserfüllungsabteilung sein, wenn sie eine Bestellung für Koala-Bären sehen. Die Lehre daraus ist, dass Sie wirklich vorsichtig mit den Daten umgehen sollten, die Sie in einer POST- oder PUT-Anforderung akzeptieren.
Um dieses Problem zu vermeiden, ändern Sie die PostOrder Methode, um eine OrderDTO Instanz zu übernehmen. Verwenden Sie die OrderDTO, um den Order zu erstellen.
var order = new Order()
{
Customer = User.Identity.Name,
OrderDetails = (from item in dto.Details select new OrderDetail()
{ ProductId = item.ProductID, Quantity = item.Quantity }).ToList()
};
Beachten Sie, dass wir die Eigenschaften ProductID und Quantity verwenden und alle Werte ignorieren, die der Client entweder für den Produktnamen oder den Preis gesendet hat. Wenn die Produkt-ID ungültig ist, verstößt sie gegen die Fremdschlüsseleinschränkung in der Datenbank, und das Einfügen schlägt fehl, wie er sollte.
Hier ist die vollständige PostOrder Methode:
public HttpResponseMessage PostOrder(OrderDTO dto)
{
if (ModelState.IsValid)
{
var order = new Order()
{
Customer = User.Identity.Name,
OrderDetails = (from item in dto.Details select new OrderDetail()
{ ProductId = item.ProductID, Quantity = item.Quantity }).ToList()
};
db.Orders.Add(order);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, order);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = order.Id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
Fügen Sie schließlich das Authorize-Attribut dem Controller hinzu:
[Authorize]
public class OrdersController : ApiController
{
// ...
Jetzt können nur registrierte Benutzer Bestellungen erstellen oder anzeigen.