إرجاع البيانات من Web API بتنسيق XML بدلاً من JSON

-

كما تعلمنا سابقا أن ASP.NET Core يقوم بإرجاع البيانات على شكل  JSONبشكل افتراضيًا ما عدا في حال كان المخرج من نوع String.
ارجع الى API السابقة وشوف شكل النتيجة بعد التنفيذ، مثل GetAllCourses (شوف الصورة)


للتذكير استخدمنا Securty KEy في API وكان الكود 
if (!Authenticate())
                return Unauthorized();
يعني اذا حاولت تشغل التطبيق الان برجع خطأ (الصورة)



الان عطل هذا الكود حتي يتنفذ المشروع 
يمكن ايضا عرض النتائج على شكل XML بدلاً من JSON .وحتي نعمل هذا التغيير لازم إضافة method التالية

AddXmlDataContractSerializerFormatters()
الى ملف Program.cs والاضافة بتكون باضافة الكود التالي :

builder.Services.AddControllers(options => options.RespectBrowserAcceptHeader = true).AddXmlSerializerFormatters().AddXmlDataContractSerializerFormatters();

من المهم ايضا نزيد attribute  التالية [Produces("application/xml")] فوق API وهذا attribute  يعمل على فرض التنسيق يكون بصيغة XML 
طيب صار وقت نجرب الشغل ونشوف النتيجة: 
شغل التطبيق بالدخول الى الرابط :
https://localhost:7081/api/Course/GetAllCourses
وبتكون النتيجة :




تمام التمام الامور .

استخدام attrbuit  [Consumes(“application/xml”)] مع Web APIs

يتوفر في Web APIs الميزة attrbuit [Consumes] الي بتعمل على تحديد  أنواع البيانات التي يقبلها action او controll.
في بعض الاحيان قد نحتاج الى ارسال بيانات من نوع XML فقط الى Web APIs ،لعمل ذلك لازم نستخدم attrbuit  [Consumes(“application/xml”)]  مع controller او Action. 
تمام وحتي نفهم الموضوع اكثر نطبق مثال عملي.
نرجع الى controller الى كان اسمو CourseController ونزيد action جديد باسم : PostXmlData وبكون الكود الخاص فيه كالتالي :

[HttpPost("PostXmlData")]
        [Consumes("application/xml")]
        public async Task<IActionResult> PostXmlData([FromBody] System.Xml.Linq.XElement res)
        {
            connection = new SqlConnection(configuration.GetConnectionString("STDCS"));
            List<CoursesModel> CoursesModelList = new List<CoursesModel>();
            try
            {
                string sqlQuery = "declare @CourseNumber nvarchar(10)=@@#" + res.Element("CourseNumber").Value + "@@#, @CourseName nvarchar(100)=@@#" + res.Element("CourseName").Value  + "@@#, @CourseDescription nvarchar(500)=@@#" + res.Element("CourseDescription").Value  + "@@#, @Price money=@@#" + res.Element("Price").Value  + "@@#, @Capacity int=@@#" + res.Element("Capacity").Value + "@@# insert into Courses( CourseNumber, CourseName, CourseDescription, Price, Capacity, CreatedDate) select  @CourseNumber, @CourseName, @CourseDescription, @Price, @Capacity,getdate()";
                DbProviderFactory dbFactory = DbProviderFactories.GetFactory(connection);
                using (var cmd = dbFactory.CreateCommand())
                {
                    cmd.Connection = connection;
                    cmd.CommandType = CommandType.Text;
                    cmd.CommandText = sqlQuery;
                    using (DbDataAdapter adapter = dbFactory.CreateDataAdapter())
                    {
                        adapter.SelectCommand = cmd;
                        await Task.Run(() => adapter.Fill(Dt));
                    }
                }
            }
            catch (Exception ex)
            {
                return NotFound();
            }
            finally
            {
            }
            return Ok();
        }


لاحظ ان هذا action يحتوي على 

1. يحتوي على consume attribute – [Consumes("application/xml")] المسؤلة عن تحديد نوع الداتا الي بيتعامل معاها هذا action وهل يمكن الاستمرار ومعالجة الطلب.
2. parameter المستخدمه هنا  من النوع XElement.
3. قراءة القيم من هذا API parameter  باستخدام الامر :res.Element("CourseNumber").Value
الان دور نستدعي هذا API لعمل ذلك خلوناا نرجع لمشروع Student Portal وبعدها انتقل الى CourseController ونزيد الكود التالي : 

        public ViewResult AddCourseByXml() => View();
        [HttpPost]
        public async Task<IActionResult> AddCourseByXml(CoursesModel coursesModel)
        {
            CoursesModel ContentCoursesModel = new CoursesModel();
            using (var httpClient = new HttpClient())
            {
                StringContent content = new StringContent(ConvertObjectToXMLString(coursesModel), Encoding.UTF8, "application/xml");
                using (var response = await httpClient.PostAsync("https://localhost:7081/api/Course/PostXmlData", content))
                {
                    string apiResponse = await response.Content.ReadAsStringAsync();
                    ContentCoursesModel = JsonConvert.DeserializeObject<CoursesModel>(apiResponse);
                }
            }
            return View(ContentCoursesModel);
        }
        string ConvertObjectToXMLString(object classObject)
        {
            string xmlString = null;
            XmlSerializer xmlSerializer = new XmlSerializer(classObject.GetType());
            using (MemoryStream memoryStream = new MemoryStream())
            {
                xmlSerializer.Serialize(memoryStream, classObject);
                memoryStream.Position = 0;
                xmlString = new StreamReader(memoryStream).ReadToEnd();
            }
            return xmlString;
        }

لاحظ ان هنا الاشياء التالية: 

1.في StringContent class حددنا parameter رقم 3 من نوع application/xml.
2. انشانا function باسم  ConvertObjectToXMLString الذي يعمل على تحويل object الى XML ويعيد النتائج على شكل XML التي سنرسلها الى API الي اسمو PostXmlData.
تمام بعد نعمل View الي من خلالو بنرسل البيانات الى API ، انشي View بالنقر يمين فوق action مثل ما تعلمنا سابقا، وبعدها ضيف الكود التالي الى هذا View : 
@model CoursesModel
@{ Layout = "_Layout"; ViewBag.Title = "Add a Course";}
 
<h2>AddCourseByXml </h2>
<form asp-action="AddCourses" method="post">
    <div class="form-group">
        <label for="CourseNumber">Course #:</label>
        <input class="form-control" name="CourseNumber" />
    </div>
    <div class="form-group">
        <label for="CourseName">Course Name:</label>
        <input class="form-control" name="CourseName" />
    </div>
    <div class="form-group">
        <label for="CourseDescription">Course Description:</label>
        <input class="form-control" name="CourseDescription" />
    </div>
     <div class="form-group">
        <label for="Price">Price:</label>
        <input class="form-control" name="Price" />
    </div>
     <div class="form-group">
        <label for="Capacity">Capacity:</label>
        <input class="form-control" name="Capacity" />
    </div>
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Add</button>
    </div>
</form>
 
@if (Model != null)
{
    <h2>Add New Course</h2>
    <table class="table table-sm table-striped table-bordered m-2">
        <thead>
            <tr>
                <th>Course ID</th>
                <th>Course Number</th>
                <th>Course Description</th>
                <th>Price </th>
                 <th>Capacity </th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>@Model.CoursesId</td>
                <td>@Model.CourseNumber</td>
                <td>@Model.CourseDescription</td>
                <td>@Model.Price</td>
                <td>@Model.Capacity</td>
            </tr>
        </tbody>
    </table>
}

اخيرا تشغيل التطبيق حاول تشغيل التطبيق ورسالنا لنشوف النتيجة.


التحكم في تنسيق Web API باستخدام “Format-specific” Methods 

يمكن أن عرض النتائح في Web API باكثر من طريقة(XML, JSON) دون تحديد النوع .ولتطبيق هذا الشي لازم تطبيق السمة FormatFilter.

طيب تمام كيف ممكن نستخدما:

ببساطة بنزيد الكود التالي فوق action 

[HttpGet("ShowReservation.{format}"), FormatFilter]