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ünmemesi gerekiyor! Çözüm, müşterilerin görebilmesi gereken özelliklerin bir alt kümesini içeren bir veri aktarım nesnesi (DTO) tanımlamaktır. Product örneklerini ProductDTO örneklerine dönüştürmek 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'nde 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 MapProducts yansıtmaya çağırıyoruzProductDTO:

return from p in db.Products select new ProductDTO() 
    { Id = p.Id, Name = p.Name, Price = p.Price };

MapProducts yöntemi, sonucu diğer sorgu parametreleriyle oluşturabilmemiz için bir IQueryable döndürür. 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'nde Modeller klasörüne sağ tıklayın ve OrderDTO adlı bir sınıf ekleyin. Aşağıdaki uygulamayı kullanın:

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'nde 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" seçeneğini belirleyin.
  • 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'yi tıklatın. Bu, OrdersController.cs adlı bir dosya ekler. Ardından, denetleyicinin varsayılan uygulamasını değiştirmemiz gerekir.

İlk olarak PutOrder ve DeleteOrder yöntemlerini silin. Bu örnek için müşteriler mevcut siparişleri değiştiremez veya silemez. Gerçek bir uygulamada, bu durumları işlemek için çok sayıda 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 bir OrderDTO örneğidir, Order yerine.
  • Veritabanını sipariş için sorguladığımızda, ilgili ve OrderDetail varlıkları getirmek için Product 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 almak için son yöntem.PostOrder Şu anda bu yöntem bir Order örnek alır. Ancak istemci aşağıdaki gibi 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 varolmayan bir Product varlığı içerir. İstemci 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 olacaktır. Ahlaki olan, POST veya PUT isteğinde kabul ettiğiniz veriler konusunda gerçekten dikkatli olmanızdır.

Bu sorunu önlemek için PostOrder yöntemini, bir OrderDTO örneği alacak şekilde değiştirin. OrderDTO kullanarak Order oluşturun.

var order = new Order()
{
    Customer = User.Identity.Name,
    OrderDetails = (from item in dto.Details select new OrderDetail() 
        { ProductId = item.ProductID, Quantity = item.Quantity }).ToList()
};

ProductID ve Quantity özelliklerini kullandığımıza ve istemcinin hem ürün adı hem de 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, Authorize özniteliğini denetleyiciye ekleyin:

[Authorize]
public class OrdersController : ApiController
{
    // ...

Artık yalnızca kayıtlı kullanıcılar sipariş oluşturabilir veya görüntüleyebilir.