Hành động CRUD trên OData dùng Asp.Net Web API

Trong bài này chúng ta sẽ thêm một OData Controller mà có tất cả chức năng Insert Create Update Delete (Gọi chung là CRUD). ODATA theo quy chuẩn của HTTP và REST. Ngoài HTTP POST, HTTP DELETE còn có HTTP PATCH mà sẽ hiệu quả khi muốn thay đổi một thuộc tính nào đó trên entity.

Step 1: Thêm OData Controller (hỗ trợ hành động CRUD)

Hãy thêm một Web API Controller mà sẽ trao HTTP requests dựa trên OData URI “/odata/Tutors”. Click phải vào folder controller ->Chọn Add->Name the controller “TutorsController” và chọn “Empty API Controller” Template.

Như đã làm trước đây chúng ta có “TutorsController” từ lớp “EntitySetController“, Chúng ta thêm Get(), GetEntityByKey(int key) và CreateEntity(Tutor entity)

 public class TutorsController : EntitySetController<Tutor, int>
    {
        LearningContext ctx = new LearningContext();

        [Queryable()]
        public override IQueryable<Tutor> Get()
        {
            return ctx.Tutors.AsQueryable();
        }

        protected override Tutor GetEntityByKey(int key)
        {
            return ctx.Tutors.Find(key);
        }

        protected override int GetKey(Tutor entity)
        {
            return entity.Id;
        }

        protected override Tutor CreateEntity(Tutor entity)
        {
            Tutor insertedTutor = entity;
            insertedTutor.UserName = string.Format("{0}.{1}",entity.FirstName, entity.LastName);
            insertedTutor.Password = Helpers.RandomString(8);
            ctx.Tutors.Add(insertedTutor);
            ctx.SaveChanges();
            return entity;
        }
  }

Vào URI “odata/Tutors” sẽ trông như sau :

alt

Bước 2: Testing OData Header

Nhìn request trên bạn sẽ thấy rằng status code là 201 có nghĩa là reponse body chứa đựng một Tutor mới được tạo ra. Nhưng nếu client không muốn trả về gấp đôi một entity của đối tượng Tutor tạo ra vậy thì ODATA cho phép chúng sta gửi đi một prefer header với yêu cầu là cần trả về entity đã tạo ra. Giá trị mặc định cho header là “return-content”. Và nếu chúng ta muons thực hiện một POST và truyền một prefer header với giá trị “return-no-content” thì server sẽ trả về 204 no contend

Bước 3: Resource Deletion

Chúng ta cần override phương thức Delete(int key) cho nên bất kỳ một yêu cầu HTTP DELETE gửi tới URI “/odata/Tutors sẽ được trao bởi phương thức này

 public override void Delete(int key)
	{
		var tutor = ctx.Tutors.Find(key);
		if (tutor == null)
		{
			throw new HttpResponseException(HttpStatusCode.NotFound);
		}

		ctx.Tutors.Remove(tutor);
		ctx.SaveChanges();
	}

Để test chúng ta cần yêu cầu HTTP DELETE tớ URI “OData/Tutors(12)” và nếu tutor tồn tại thì response sẽ là 204 content. Điều đáng đề cập ở đây là nếu chúng ta cố gắng delete cái không tồn tại thì sẽ throw HttpResponseException với status 404 cùng với response body rỗng. Có thể làm lỗi này với cách khác bằng cách trả về HttpResponseException với loại Microsoft.Data.OData.ODataError

Bước 4: Trả về OData Errors

Để fix điều trên tôi tạo ra một lớp helper mà trả về ODataError

 public static class Helpers
    {
        public static HttpResponseException ResourceNotFoundError(HttpRequestMessage request)
        {
            HttpResponseException httpException;
            HttpResponseMessage response;
            ODataError error;

            error = new ODataError
            {
                Message = "Resource Not Found - 404",
                ErrorCode = "NotFound"
            };

            response = request.CreateResponse(HttpStatusCode.NotFound, error);

            httpException = new HttpResponseException(response);

            return httpException;
        }
    }

Bằng cách nhìn lên code trên bạn sẽ thấy rằng chẳng có gì đặc biệt ở đây chúng ta chỉ trả về một đối tượng loại ODataError trong response body và bạn có thể thiết lập message và errorcode cho có ý nghĩa hơn đối với service OData của bạn. Bây giờ thay vì ném một ngoại lệ trực tiếp trong controller chúng ta sẽ gọi đến helper như sau :

if (tutor == null)
	{
		throw Helpers.ResourceNotFoundError(Request);
	}

Bước 5: Thêm Partial Updates (PATCH)

Trong trường hợp chúng ta muốn thay đổi 1 hoặc 2 thuộc tính trong số 30 thuộc tính chả hạn. Nó sẽ rất hữu hiệu nếu chúng ta chỉ gửi đi những gì cần thay đổi cũng như nó sẽ rất hiệu quả trên databasee nếu chúng ta tạo ra tạo ra câu lệnh chỉ cập nhật trường cần cập nhật. Để đạt được điều này chúng ta override phương thức PatchEntity() như code sau :

protected override Tutor PatchEntity(int key, Delta<Tutor> patch)
        {
            var tutor = ctx.Tutors.Find(key);
            if (tutor == null)
            {
                throw Helpers.ResourceNotFoundError(Request);
            }
            patch.Patch(tutor);
            ctx.SaveChanges();
            return tutor;
        }

Thuộc tính thay đổi thuộc về key/value trong response body nhờ bởi Delta<T> OData khiến nó dễ dàng thực hiện cập nhật từng phần trên entity. Để test chúng ta thực hiện HTTP Patch request tới URI “/odata/Tutors(10)” mà sẽ thay đổi chỉ thuộc tính LastName cho Tutor, yêu cầu như sau :

alt

Trước khi thực hiện hãy mở SQL Server Profile để xem database mà sẽ tạo ra để cập nhật Tutor này. Bạn sẽ thấy rằng sự hữu hiệu sử dụng Patch update khi muốn thay đổi một thuộc tính nào đó và câu lệnh tạo ra chỉ cập nhật trên thuộc tính cần thay đổi.

alt