Bölüm 6: Ürün ve Sipariş Denetleyicileri Oluşturma

tarafından Rick Anderson

Tamamlanan Projeyi İndir

Ü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.

Denetleyici ekle iletişim kutusunun ekran görüntüsü.

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 GetProductwhere 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.

Denetleyici ekle iletişim kutusunun ekran görüntüsü. OrdersController metin kutusuna yazılır.

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, Orderyerine bir OrderDTO örnektir.
  • Veritabanını sipariş için sorgularken, ilgili OrderDetail ve Product 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 PostOrderalmak 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 Orderiç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.