Bölüm 6: Ürün ve Sipariş Denetleyicileri Oluşturma
tarafından Rick Anderson
Ürün Denetleyicisi Ekleme
Yönetici denetleyicisi, yönetici ayrıcalıklarına sahip kullanıcılar içindir. Öte yandan müşteriler ürünleri görüntüleyebilir ancak oluşturamaz, güncelleştiremez veya silemez.
Get yöntemlerini açık bırakırken Post, Put ve Delete yöntemlerine erişimi kolayca kısıtlayabiliriz. Ancak bir ürün için döndürülen verilere bakın:
{"Id":1,"Name":"Tomato Soup","Price":1.39,"ActualCost":0.99}
Özelliğin ActualCost
müşteriler tarafından görülememesi gerekir! Çözüm, müşterilerin görebileceği bir özellik alt kümesi içeren bir veri aktarım nesnesi (DTO) tanımlamaktır. Örnekleri örneklere ProductDTO
yansıtmak Product
için LINQ kullanacağız.
Models klasörüne adlı ProductDTO
bir sınıf ekleyin.
namespace ProductStore.Models
{
public class ProductDTO
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Şimdi denetleyiciyi ekleyin. Çözüm Gezgini'da Denetleyiciler klasörüne sağ tıklayın. Ekle'yi ve ardından Denetleyici'yi seçin. Denetleyici Ekle iletişim kutusunda denetleyiciyi "ProductsController" olarak adlandırın. Şablon'un altında Boş API denetleyicisi'ni seçin.
Kaynak dosyadaki her şeyi aşağıdaki kodla değiştirin:
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);
}
}
}
Denetleyici yine veritabanını sorgulamak için öğesini OrdersContext
kullanır. Ancak örnekleri doğrudan döndürmek Product
yerine bunları örneklere ProductDTO
yansıtmak için çağırırızMapProducts
:
return from p in db.Products select new ProductDTO()
{ Id = p.Id, Name = p.Name, Price = p.Price };
MapProducts
yöntemi bir IQueryable döndürür, böylece sonucu diğer sorgu parametreleriyle oluşturabiliriz. Bunu, sorguya GetProduct
where yan tümcesi ekleyen yönteminde görebilirsiniz:
var product = (from p in MapProducts()
where p.Id == 1
select p).FirstOrDefault();
Sipariş Denetleyicisi Ekleme
Ardından, kullanıcıların siparişleri oluşturmasına ve görüntülemesine olanak tanıyan bir denetleyici ekleyin.
Başka bir DTO ile başlayacağız. Çözüm Gezgini,Models klasörüne sağ tıklayın ve Aşağıdaki uygulamayı kullan adlı OrderDTO
bir sınıf ekleyin:
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; }
}
}
Şimdi denetleyiciyi ekleyin. Çözüm Gezgini'da Denetleyiciler klasörüne sağ tıklayın. Ekle'yi ve ardından Denetleyici'yi seçin. Denetleyici Ekle iletişim kutusunda aşağıdaki seçenekleri ayarlayın:
- Denetleyici Adı'nın altına "OrdersController" yazın.
- Şablon'un altında "Entity Framework kullanarak okuma/yazma eylemleriyle API denetleyicisi"ni seçin.
- Model sınıfı'nın altında "Order (ProductStore.Models)" öğesini seçin.
- Veri bağlam sınıfı'nın altında "OrdersContext (ProductStore.Models)" öğesini seçin.
Ekle'ye tıklayın. Bu, OrdersController.cs adlı bir dosya ekler. Ardından, denetleyicinin varsayılan uygulamasını değiştirmemiz gerekir.
İlk olarak ve DeleteOrder
yöntemlerini silinPutOrder
. Bu örnek için müşteriler mevcut siparişleri değiştiremez veya silemez. Gerçek bir uygulamada, bu durumlarla başa çıkabilmek için çok fazla arka uç mantığına ihtiyacınız olacaktır. (Örneğin, sipariş zaten gönderildi mi?)
GetOrders
Yalnızca kullanıcıya ait siparişleri döndürmek için yöntemini değiştirin:
public IEnumerable<Order> GetOrders()
{
return db.Orders.Where(o => o.Customer == User.Identity.Name);
}
GetOrder
yöntemini aşağıdaki gibi değiştirin:
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
}
};
}
yönteminde yaptığımız değişiklikler şunlardır:
- Dönüş değeri,
Order
yerine birOrderDTO
örnektir. - Veritabanını sipariş için sorgularken, ilgili
OrderDetail
veProduct
varlıkları getirmek için DbQuery.Include yöntemini kullanırız. - Projeksiyon kullanarak sonucu düzleştirmemiz gerekir.
HTTP yanıtı, miktarları olan bir ürün dizisi içerir:
{"Details":[{"ProductID":1,"Product":"Tomato Soup","Price":1.39,"Quantity":2},
{"ProductID":3,"Product":"Yo yo","Price":6.99,"Quantity":1}]}
Bu biçim, istemcilerin iç içe varlıklar (sipariş, ayrıntılar ve ürünler) içeren özgün nesne grafını kullanmasından daha kolaydır.
Bunu dikkate PostOrder
almak için son yöntem. Şu anda bu yöntem bir Order
örnek alır. Ancak istemci aşağıdakine benzer bir istek gövdesi gönderirse ne olacağını göz önünde bulundurun:
{"Customer":"Alice","OrderDetails":[{"Quantity":1,"Product":{"Name":"Koala bears",
"Price":5,"ActualCost":1}}]}
Bu iyi yapılandırılmış bir düzendir ve Entity Framework bunu veritabanına memnuniyetle ekler. Ancak daha önce var olmayan bir Product varlığı içeriyor. müşteri veritabanımızda yeni bir ürün oluşturdu! Bu, koala ayıları için bir sipariş gördüklerinde sipariş karşılama departmanına sürpriz olacak. Asıl önemli olan, POST veya PUT isteğinde kabul ettiğiniz veriler konusunda gerçekten dikkatli olmanızdır.
Bu sorunu önlemek için yöntemini örnek alacak şekilde OrderDTO
değiştirinPostOrder
. OrderDTO
oluşturmak Order
için kullanın.
var order = new Order()
{
Customer = User.Identity.Name,
OrderDetails = (from item in dto.Details select new OrderDetail()
{ ProductId = item.ProductID, Quantity = item.Quantity }).ToList()
};
ve Quantity
özelliklerini kullandığımıza ve istemcinin ProductID
ürün adı veya fiyat için gönderdiği değerleri yoksaydığımıza dikkat edin. Ürün kimliği geçerli değilse, veritabanındaki yabancı anahtar kısıtlamasını ihlal eder ve ekleme işlemi gerektiği gibi başarısız olur.
Tam yöntem şu şekildedir PostOrder
:
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);
}
}
Son olarak, Denetleyiciye Authorize özniteliğini ekleyin:
[Authorize]
public class OrdersController : ApiController
{
// ...
Artık siparişleri yalnızca kayıtlı kullanıcılar oluşturabilir veya görüntüleyebilir.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin