כתיבת web api בפרויקט ASP.NET
הפרוייקט שאני כותב עכשיו עוסק בממשק פשוט שמקבל אדם שמשלם כסף, וישנה
אפשרות לבחור מזומן או צק. במידה וייבחר צק ניתן להזין את הצקים שבהם הלקוח שילם.
תמיד עבדתי עם הנדלרים להעביר את הנתונים ומכיוון שנראה לי די טיפשי
להעביר עוד מתווך בין הקליינט לסרבר,
בדקתי את שלושת האפשרויות הפופולאריות:
בדקתי את שלושת האפשרויות הפופולאריות:
- WCF שנראה לפי המדריכים שמיועד
לדברים יותר רציניים, והוא יותר כבד מליישומי אינטרנט פשוטים.
- WEB SERVER שממש קל ליישום, אבל
הבעיה שכל הפונקציות שמקבלות את הנתונים הם static, שזו פונקציה יחידנית שאיננה מתקשרת עם
פונקציות אחרות. וגם כל פונקציה שיורשת ממנה או ממשיכה ממנה הינה static. הרגשתי שזה מגביל
אותי.
לכן בחרתי לעבוד עם web api שמתקשרת רק על בקשות http. שנראה די פשוט, ומאוד פשוט לתפעול עם מנגנון
הפניית הכותבות (route).
הצרות התחילו שמסתבר שכל הדוגמאות, הפרויקטים הינם הMVC, דבר שמעודד מחד - כי זה אומר שזה חלק מהעתיד,
מצד שני לא מצאתי פרויקט נורמאלי אחד שגם עובד בASPNET (למה אני מתקשה לעבוד בMVC זה נושא לפוסט אחר).
החלטתי לכתוב מדריך שבעצם ילווה את תהליך הלמידה שלי, ולכן כמובן הכל
בעירבון מוגבל.
חרישת הרשת העלתה פרוייקט אחד, שמהווה פרויקט רציני שגם נראה שעובד בgithub. שעיקר הדוגמא
מתבססת עליו. כמובן, בצורה הרבה יותר פשוטה.
והסבר לפרוייקט בצורה מאירת פנים
http://weblog.west-wind.com/posts/2012/Aug/21/An-Introduction-to-ASPNET-Web-API
http://weblog.west-wind.com/posts/2012/Aug/21/An-Introduction-to-ASPNET-Web-API
לאחר שפתחנו פרוייקט רגיל של asp.net, ננתח את המחלקה של התשלום ואת האופן שבו אנחנו
רוצים להשתמש בה. נוסיף מחלקה חדשה:
חשוב. חובה שזה יהיה בתקיית App_Code אחרת המחלקות לא יזוהו בפרוייקט.
public class payStu
{
public int idPay { get; set; }//PK
public DateTime datePay { get; set; }
public int idSchool { get; set; }
public int idSnif { get; set; }
public int idSecretary { get; set; }//id name in the login system
public string namePay { get; set; }
public string nameStu { get; set; }
public int paySum { get; set; }
public string payDis { get; set; }
public string payType { get; set; } //1- cash num-idzkList
public string payFor { get; set; }
public virtual List<zk> zkList { get; set; }
public payStu()
{
zkList = new List<zk>();
}
public void AddZK(int idzkList, int zkBankNum, int zkBranchNum, int zkAccountNum, decimal zkSum)
{
this.zkList.Add(new zk()
{
idzkList = idzkList,
zkBankNum = zkBankNum,
zkBranchNum = zkBranchNum,
zkAccountNum = zkAccountNum,
zkSum = zkSum
});
}
}
כיוון שייתכן שנקבל צ'ק, נצטרך לבנות מחלקה נוספת לצ'קים. הקישור
אליהם ייעשה דרך payType. ערך 1 מהווה הוכחה שזהו מזומן, אחרת יהיה שם
תיאור של ID של הצק. (כל קבוצת הצ'קים שימסרו על ידי הלקוח באותו מעמד יקבלו
אותו ID , כך שנוכל לקשר את כל הצקים לאותה עסקה).
public class zk
{
public zk()
{}
public int idzkList { get; set; }
public int zkBankNum { get; set; } // num of bank
public int zkBranchNum { get; set; } // num of snif bank
public int zkAccountNum { get; set; } //num of account
public decimal zkSum { get; set; }
}
================================
כעת, ניצור את דף הגלובלי Global.asax. ניצור את הכללים שבהם האתר ינתח את כתובת הurl שמגיעות אליו.
using System.Web.Http;
using System.Web.Routing;
using System.Web.Http;
using System.Net.Http;
using System.Web.Http.WebHost;
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHttpRoute(
name: "API",
routeTemplate: "pay/{ payDi }",
defaults: new { payDi = System.Web.Http.RouteParameter.Optional
}
);
}
אפשרות נוספת היא להגדיר פעולה ברירת מחדל, תחת המשתנה defaults, באופן שכזה:
defaults: new { action = "functionDefaults", payDi = System.Web.Http.RouteParameter.Optional }
ואז בקונטרולר, נוסיף את השדה [ActionName("functionDefaults")] מעל הפונקציות שאנחנו רוצים לשייך לפעולה הדיפולטיבית.
לדו'
[HttpPost]
[ActionName("functionDefaults")]
public void Post(int t)
{
}
במידה ופתחנו פרויקט אינטרנט, נצטרך להוסיף ב Global.asax
<%@ Import Namespace="System.Web.Routing" %>
<%@ Import Namespace="System.Web.Http" %>
<%@ Import Namespace="System.Net.Http" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Code
that runs on application startup
RouteTable.Routes.MapHttpRoute(
name: "API",
routeTemplate: "api/{controller}/{payDi}",
defaults: new { payDi = System.Web.Http.RouteParameter.Optional
});
}
</script>
לname API אין שום משמעות, אלא לתאר את תפקיד המפקח. יותר חשוב הכלל routeTemplate: "pay/{title}", שמורה שכל כתובת URL שיש בה את "תיקייה" pay ולאחריה כתובת יש לטפל בה. לדו' www.pay.com/pay/choen
- במידה וישנן בעיות עם הספריות. נוסיף ברשימת פקודות
Install-Package Microsoft.AspNet.WebApi -Version 4.0.30506
או רפרנסים לספריות שחסרות.
========================================
לאחר מכן
נוסיף את controller (מפקח) שהוא מבצע את הטיפול בפניות. יש
לשים לב ששמו יסתיים בcontroller כדי שהשרת יוכל לזהות אותו כמפקח. לפרויקט נוסיף אייטם
חדש:
ונקרא לו payController.
ניתן לפתוח תיקייה של Controller, ולאסוף שם את כל המפקחים.
בקובץ web.config יתווסף לנו:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5">
<assemblies>
<add assembly="System.Net.Http, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=B03F5F7F11D50A3A" />
<add assembly="System.Net.Http.WebRequest, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
</assemblies>
</compilation>
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
</configuration>
נסתכל לדוגמא באחד מן הפונקציות האוטומטיות שנכתבו
// POST api/<controller>
public void Post([FromBody]string value)
{
}
כל פקודה שנשלחת מהקליינט בPOST תטופל בפקודה זו.
במידה ונשלח פקודת GET, ישנן 2 אפשרויות, שהמפקח מטפל בפונקציות לפי הבקשה:
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET
api/<controller>/5
public string Get(int id)
{
return "value";
}
במידה וזו תהיה רק בקשה GET, המפקח ישלח את כל הנתונים "value1", "value2", במידה ובבקשת הGET יהיה לאחר שם מפקח גם מספר, הוא יזהה שהכוונה
למזהה ID ויתן לנו ערך התואם לid המבוקש.
כל בקשה שנשלחת בGET מגיעה לכל הפונקציות
שמתחילות בGET, GetPay GetZK וכו'.
נבנה את המפקח שיטפל בנתונים
public void Post(payStu pay)
{
}
=========================
כעת נתחיל לעבוד על הקליינט, נוסיף דף ראשי defult.aspx
נוסיף את ספריית ה jQuery, לחיצה על הפרוייקט' לחצן ימני ועם NuGet נוסיף את הספרייה jquery (זו הספרייה הכי פופולרית, לכן רוב הסיכויים שתהיה ראשונה).
הפרוייקט גם יעדכן אותנו שהוא מעדכן את קובץ ה config.web.
נוסיף את ספריית ה jQuery, לחיצה על הפרוייקט' לחצן ימני ועם NuGet נוסיף את הספרייה jquery (זו הספרייה הכי פופולרית, לכן רוב הסיכויים שתהיה ראשונה).
הפרוייקט גם יעדכן אותנו שהוא מעדכן את קובץ ה config.web.
נוסיף את הספרייה לתוך הפרוייקט, פשוט נגרור את הקובץ לתוך הפרוייקט
אחרי הtitle
<script src="Scripts/jquery-2.1.0.min.js"></script>
<script type="text/javascript">
var pay = {
"idPay": 0,
"namePay": "mose",
"nameStu": "choen",
"paySum":"100",
"payDis":"מאה שקלים חדשים",
"payType": 1234,
"payFor": "תשלום חודשי למוסד",
"zkList": [
{ "idzkList": 1234, "zkBankNum": 32, "zkBranchNum": 5656, "zkAccountNum":
7877, "zkSum": 78.64 },
{ "idzkList": 1234, "zkBankNum": 32, "zkBranchNum": 5656, "zkAccountNum":
676, "zkSum": 8989 }
]
}
$.ajax({
type: 'POST',
contentType: "application/json",
data: JSON.stringify(pay),
success: function (result) {
alert(result);
}
});
</script>
את הנתונים של התשלום, ואת הצקים
נשייך לרשומה 1234, שתהווה את "המקבץ" של הצקים ששולמו בתשלום הנוכחי. נריץ את הפרוייקט ונוודא שאכן
כל המשתנים הגיעו לשרת.
===============================
תקלות שעלולות לצוץ:
- אני לא יודע למה, אבל אין לשים את הדף בתיקיה חוץ מהroot הראשי - לפחות אצלי, הפרויקט לא עבד.
- בקובץ הקונפיגרציה, הקובץ DLL של הרוטינה נטען כך:
תקלות שעלולות לצוץ:
- אני לא יודע למה, אבל אין לשים את הדף בתיקיה חוץ מהroot הראשי - לפחות אצלי, הפרויקט לא עבד.
- בקובץ הקונפיגרציה, הקובץ DLL של הרוטינה נטען כך:
<!--הוספת DLL-->
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Net.Http, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
</assemblies>
</compilation>
משום מה, היה רגעים שהVS לא זיהה את הקובץ DLL, וטען שאני צריך לעדכן. אז צריך להוסיף גם את ההגדרות האלה תחת התגית configuration:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
אין תגובות:
הוסף רשומת תגובה