6. Bölüm: ürün ve sipariş denetleyicileri oluşturma

, Mike te son

Tamamlanmış projeyi indir

Ürün denetleyicisi ekleme

Yönetici denetleyicisi, yönetici ayrıcalıklarına sahip kullanıcılar içindir. Diğer yandan müşteriler ürünleri görüntüleyebilir, ancak oluşturamaz, güncelleştiremez veya silemez.

Post, put ve DELETE yöntemlerine erişimi kolayca kısıtlayabiliriz ve Get yöntemlerinin açık bırakılması gerekir. Ancak bir ürün için döndürülen verilere göz atın:

{"Id":1,"Name":"Tomato Soup","Price":1.39,"ActualCost":0.99}

ActualCost özelliği müşterilere görünür olmamalıdır! Çözüm, müşterilere görünür olması gereken özelliklerin bir alt kümesini içeren bir veri aktarımı nesnesi (DTO) tanımlamaktır. Örnekleri ProductDTO için LINQ for Project Product örnekleri kullanacağız.

Modeller klasörüne ProductDTO adlı 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, 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. Şablonaltı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 hala veritabanını sorgulamak için OrdersContext kullanır. Ancak Product örnekleri doğrudan döndürmek yerine, onları ProductDTO örneklerine eklemek için MapProducts çağırdık:

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

MapProducts yöntemi bir IQueryabledöndürür, bu nedenle sonucu diğer sorgu parametreleriyle oluşturabilirsiniz. Bunu sorguya bir WHERE yan tümcesi ekleyen GetProduct yönteminde görebilirsiniz:

var product = (from p in MapProducts() 
    where p.Id == 1
    select p).FirstOrDefault();

Sipariş denetleyicisi ekleme

Daha sonra, kullanıcıların sipariş oluşturmalarına ve görüntülemesine imkan tanıyan bir denetleyici ekleyin.

Başka bir DTO ile başlayacağız. Çözüm Gezgini, modeller klasörüne sağ tıklayın ve OrderDTO adlı bir sınıf ekleyerek 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, 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ıbölümünde "orderscontroller" yazın.
  • Şablonaltında, "Entity Framework kullanarak okuma/yazma EYLEMLERI ile API denetleyicisi ' ni seçin.
  • Model sınıfıaltında "Order (productstore. modeller)"öğesini seçin.
  • Veri bağlamı sınıfıaltında "OrdersContext (productstore. modeller)"öğesini seçin.

Ekle'yi tıklatın. Bu, OrdersController.cs adlı bir dosya ekler. Sonra, denetleyicinin varsayılan uygulamasını değiştirmemiz gerekiyor.

İlk olarak, PutOrder ve DeleteOrder yöntemlerini silin. Bu örnekte, 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 vardır. (Örneğin, sipariş zaten sevk edildi mı?)

GetOrders yöntemini yalnızca kullanıcıya ait olan siparişleri döndürecek şekilde 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
                      }
    };
}

Bu yöntemde yaptığımız değişiklikler aşağıda verilmiştir:

  • Dönüş değeri, bir Orderyerine bir OrderDTO örneğidir.
  • Sıraya yönelik veritabanını sorgulıyoruz, ilgili OrderDetail ve Product varlıklarını getirmek için dbquery. Include metodunu kullanırız.
  • Bir projeksiyon kullanarak sonucu düzettik.

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 geçmiş varlıklar (sipariş, Ayrıntılar ve ürünler) içeren özgün nesne grafiğinden daha kolay kullanmasını sağlar.

PostOrdergöz önünde bulundurmanız gereken son yöntem. Bu yöntem şu anda bir Order örneği alır. Ancak, bir istemci şöyle bir istek gövdesi gönderirse ne olacağını düşünün:

{"Customer":"Alice","OrderDetails":[{"Quantity":1,"Product":{"Name":"Koala bears", 
"Price":5,"ActualCost":1}}]}

Bu iyi yapılandırılmış bir sıradır ve Entity Framework, veritabanını veritabanına eklemesi gerekir. Ancak daha önce mevcut olmayan bir ürün varlığını içerir. İstemci, veritabanımızda yeni bir ürün oluşturdu! Bu, Koala yatak için bir sipariş görtiklerinde departmanı karşılama bölümünün bir şaşırmasını sağlar. Moral, bir POST veya PUT isteğinde kabul ettiğiniz veriler hakkında gerçekten dikkatli olun.

Bu sorundan kaçınmak için PostOrder yöntemini bir OrderDTO örneği alacak şekilde değiştirin. Orderoluşturmak için OrderDTO 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()
};

ProductID ve Quantity özelliklerini kullandığımızda, istemcinin ürün adı veya fiyat için gönderdiği tüm değerleri yok saydığımızda dikkat edin. Ürün KIMLIĞI geçerli değilse, veritabanındaki yabancı anahtar kısıtlamasını ihlal eder ve gerektiğinde ekleme işlemi başarısız olur.

İşte PostOrder yöntemi aşağıda verilmiştir:

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 Yetkilendir özniteliğini ekleyin:

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

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