Web API ในโซลูชัน MVC ในโครงการแยกต่างหาก


88

ฉันกำลังสร้างโครงการ MVC4 ใหม่และการวิจัยทำให้ฉันเชื่อว่าตอนนี้การสื่อสารจากจาวาสคริปต์ไปยังฝั่งเซิร์ฟเวอร์ทำได้ดีกว่าผ่านเฟรมเวิร์ก Web API มากกว่าการดำเนินการของคอนโทรลเลอร์ ความเข้าใจของฉันถูกต้องในเรื่องนี้หรือไม่?

ฉันคิดว่าฉันสามารถแบ่งปันคุณลักษณะทั้งหมดของฉันและอื่น ๆ ระหว่างเว็บ API และตัวควบคุม MVC ได้ดูเหมือนจะไม่เปลี่ยนแปลงครั้งใหญ่สำหรับฉัน

เมื่อฉันตั้งค่าแอปพลิเคชันฉันต้องการแยกส่วนประกอบออกเป็นโปรเจ็กต์ แผนของฉันคือมีโครงการ MVC และโครงการเว็บ API แต่ฉันได้พบกับปัญหา ตัวอย่างเช่นฉันมี 2 แอพเช่นนี้การตั้งค่าเส้นทางแยกต่างหาก ฯลฯ เป็นต้น

ดังนั้นคำถามของฉันคือในแอปพลิเคชัน MVC เฟรมเวิร์ก API ของเว็บควรอยู่ในโปรเจ็กต์เดียวกันหรือควรแยกเว็บ API ออกเป็นโปรเจ็กต์ของตัวเองและแก้ไขปัญหา

คำตอบ:


110

น่าเสียดายที่คุณคิดผิดเกี่ยวกับเรื่องนี้ - ฉันคิดว่าฉันสามารถแบ่งปันคุณลักษณะทั้งหมดของฉัน ฯลฯ ระหว่าง web api และตัวควบคุม mvc ดังนั้นในหน้ามันดูเหมือนจะไม่เปลี่ยนแปลงครั้งใหญ่สำหรับฉัน

หลายแนวคิดที่ใช้โดย Web API และ MVC แม้ว่าจะคล้ายกันในตอนแรก แต่ก็ไม่สามารถใช้ร่วมกันได้ ตัวอย่างเช่นแอตทริบิวต์ Web API คือSystem.Web.Http.Filters.Filterและแอตทริบิวต์ MVC คือSystem.Web.Mvc.Filter- และไม่สามารถใช้แทนกันได้

เช่นเดียวกันกับแนวคิดอื่น ๆ อีกมากมายเช่นการผูกโมเดล (กลไกที่แตกต่างกันโดยสิ้นเชิง) เส้นทาง (Web API ใช้ HTTPRoutes ไม่ใช่ Routes แม้ว่าทั้งคู่จะทำงานบน RouteTable ที่เป็นพื้นฐานเดียวกันก็ตาม) ตัวแก้ไขการอ้างอิง (ไม่สามารถใช้ร่วมกันได้) และอื่น ๆ - แม้ว่าจะคล้ายกันก็ตาม พื้นผิวมีความแตกต่างกันมากในทางปฏิบัติ ยิ่งไปกว่านั้น Web API ไม่มีแนวคิดเกี่ยวกับพื้นที่

ท้ายที่สุดแล้วหากสิ่งที่คุณพยายามทำคือการมีวิธีการแสดงเนื้อหา JSON ที่ "ใหม่และอินเทรนด์" ให้คิดให้ดีก่อนที่จะไปตามเส้นทางนั้น ฉันไม่แนะนำให้ปรับโครงสร้างโค้ดที่มีอยู่ใหม่อย่างแน่นอนเว้นแต่คุณจะต้องการใช้ HTTP และสร้างแอปของคุณด้วยวิธีที่ไม่พึงประสงค์

ทุกอย่างขึ้นอยู่กับสิ่งที่คุณกำลังสร้าง หากคุณกำลังเริ่มโปรเจ็กต์ใหม่และสิ่งที่คุณต้องมีก็คือการให้บริการ JSON เพื่ออำนวยความสะดวกในเว็บแอปของคุณ - หากคุณเต็มใจที่จะใช้งานกับโค้ดที่อาจซ้ำกัน (เช่นสิ่งที่ฉันกล่าวไว้ข้างต้น) Web API สามารถโฮสต์ได้อย่างง่ายดายภายใน โครงการเดียวกับ ASP.NET MVC

ฉันจะแยก Web API ออกเป็นโปรเจ็กต์แยกกันก็ต่อเมื่อคุณกำลังจะสร้าง API ที่เหมาะสมสำหรับบริการออนไลน์ของคุณซึ่งอาจจะถูกใช้โดยลูกค้าภายนอกหรือโดยอุปกรณ์ต่างๆเช่นการเติมน้ำมันแอพมือถือของคุณ


2
+1 คำตอบที่ยอดเยี่ยม ฉันคิดว่าในตอนแรกทั้ง MVC และ WebAPI อาจแชร์โค้ดบางส่วนโดยเฉพาะในกรณีของตัวกรองการผูกโมเดล ฯลฯ แต่แตกต่างกันโดยสิ้นเชิง
VJAI

5
ใช่ในสถานการณ์เช่นนี้เพียงแค่เริ่มโครงการ MVC4 ใหม่ใน Visual Studio และเมื่อได้รับแจ้งสำหรับเทมเพลตโครงการ (หน้าจอที่สอง) ให้เลือก Web API นั่นจะเป็นการติดตั้ง Web API จาก Nuget และในกรณีที่คุณอธิบายไว้ควรจะสมบูรณ์ดี สิ่งที่คุณได้รับคือไฟล์กำหนดค่า Web API แยกต่างหากที่เสียบเข้ากับ Global.asax นอกจากนี้คุณอาจต้องการแยกตัวควบคุม API ออกเป็นโฟลเดอร์แยกต่างหาก (โดยค่าเริ่มต้นจะอยู่ร่วมกับตัวควบคุม MVC) ในที่สุดเส้นทางเริ่มต้นได้รับการกำหนดค่าแยกกันอย่างชัดเจนและไม่รบกวนซึ่งกันและกัน
Filip W

9
ฉันหวังว่าหัวหน้าของฉันจะได้อ่านโพสต์นี้ก่อนที่เขาจะออกแบบโครงการปัจจุบันของเรา
Billdr

2
@FilipW ขอบคุณสำหรับคำอธิบายที่ดี ฉันยังมีแอปพลิเคชัน MVC และจะใช้ WebAPI2 เพื่อใช้บริการสำหรับแอปพลิเคชัน Android ในทางกลับกันดังที่ David Peden กล่าวไว้ด้านล่างการรักษาความปลอดภัยการบำรุงรักษาและการปรับใช้ก็มีความสำคัญเช่นกันเมื่อตัดสินใจสร้างโครงการแยกใหม่สำหรับ WebAPI ในกรณีนี้โปรดจำไว้ว่าคุณจะแนะนำอะไร หากต้องการสร้างโปรเจ็กต์แยกใหม่สำหรับ WebAPI หรือใช้โปรเจ็กต์ MVC ปัจจุบัน? ขอบคุณล่วงหน้า.
แจ็ค

1
ดีมาก "ฉันจะแยก Web API ออกเป็นโปรเจ็กต์แยกต่างหากหากคุณกำลังจะสร้าง API ที่เหมาะสมสำหรับบริการออนไลน์ของคุณซึ่งลูกค้าภายนอกหรืออุปกรณ์ต่างๆอาจใช้งานได้เช่นการเติมน้ำมันแอปบนอุปกรณ์เคลื่อนที่ของคุณ" ตอกตะปูลงบนหัวและทำให้ง่ายต่อการตัดสินใจว่าจะทำอย่างไร
ozzy432836

27

IMO ความปลอดภัยและการปรับใช้ควรขับเคลื่อนการตัดสินใจของคุณ เช่นหากแอป MVC ของคุณใช้การตรวจสอบสิทธิ์แบบฟอร์ม แต่คุณสนใจที่จะใช้การรับรองความถูกต้องขั้นพื้นฐาน (ด้วย SSL) สำหรับ API ของคุณโครงการแยกต่างหากจะทำให้ชีวิตของคุณง่ายขึ้น หากคุณต้องการโฮสต์ไซต์ของคุณที่ www.example.com แต่โฮสต์ API ของคุณเป็น api.example.com (เทียบกับ www.example.com/api) โครงการแยกต่างหากจะทำให้ชีวิตของคุณง่ายขึ้น หากคุณแยกโครงการและโดเมนย่อยออกจากกันและคุณตั้งใจจะใช้ประโยชน์จาก API ของคุณเองจากแอป MVC คุณจะต้องหาวิธีจัดการกับปัญหานโยบายแหล่งกำเนิดเดียวกันสำหรับการเรียกใช้ API ของฝั่งไคลเอ็นต์ วิธีแก้ปัญหาทั่วไปคือการใช้ประโยชน์จากjsonpหรือCORS (โดยเฉพาะอย่างยิ่งถ้าคุณสามารถทำได้)

อัปเดต (26/3/2556): การสนับสนุน CORS อย่างเป็นทางการกำลังจะมา: http://aspnetwebstack.codeplex.com/wikipage?title=CORS%20support%20for%20ASP.NET%20Web%20API


ฉันพยายามทำความเข้าใจเกี่ยวกับปัญหาเกี่ยวกับการตัดสินใจรวม Web API กับแอปพลิเคชัน MVC ของฉันหรือตั้งเป็นโครงการแยกต่างหาก ฉันสามารถปรับใช้แอป Web API HelloWorld กับโดเมนย่อยบนโฮสต์เว็บของฉันได้สำเร็จ จากโครงการแยกนี้ฉันมีแนวโน้มที่จะใช้ Model จากเว็บแอปพลิเคชัน MVC ของฉันและรหัสการโทรในโครงการแยกนั้น ดูเหมือนว่าการไปตามเส้นทางของโครงการแยกนี้อาจจะง่ายกว่า แต่คุณคิดว่าปัญหาใดที่ฉันสามารถพบได้เมื่อใช้แนวทางนี้
Ciaran Gallagher

2
ส่วนตัวฉันจะไม่ใช้โมเดลมุมมองของคุณเป็น DTO สำหรับ API ของคุณ ฉันคาดหวังว่าการตัดสินใจครั้งนั้นจะทำให้คุณเจ็บปวดอย่างหนักเนื่องจากโมเดลมุมมองและลายเซ็น API ของคุณแตกต่างกัน SoC ( en.wikipedia.org/wiki/Separation_of_concerns ) มีความสำคัญมาก
David Peden

@DavidPeden คุณแนะนำให้สร้างโปรเจ็กต์ใหม่แยกต่างหากสำหรับ WebAPI เป็นเช่นนั้นจริงหรือ? ในทางกลับกันฉันจะสร้างโปรเจ็กต์ใหม่แยกสำหรับ WebAPI (ปัจจุบันฉันมี UI Layer (MVC) และ Data Layer (Class Library) ในแอปพลิเคชันของฉันดังนั้นฉันจึงใช้ DI ด้วย แต่ฉันสงสัยว่าฉันสามารถใช้ เอนทิตีที่เก็บอินเทอร์เฟซและคลาสบทคัดย่อเดียวกันในชั้นข้อมูลสำหรับโปรเจ็กต์ WebAPI ที่สร้างขึ้นใหม่และสิ่งเดียวที่ฉันต้องทำคือสร้างตัวควบคุม WebAPI หรือฉันจะสร้างทั้งหมด (เอนทิตีที่เก็บอินเทอร์เฟซและบทคัดย่อ ) อีกครั้งสำหรับ WebAPI โปรดช่วยได้ไหม
แจ็ค

1
@ เอช. จอห์นสันเป็นการยากที่จะให้คำแนะนำทั่วไปที่มีความหมาย แต่ดูเหมือนว่าคุณจะได้รับประโยชน์จากการมีชั้นบริการแอปพลิเคชันที่ห่อหุ้มเอนทิตีและที่เก็บของคุณซึ่งสามารถใช้ประโยชน์จาก UI ของคุณทั้งสอง (MVC และ API)
David Peden

9

หลังจากประสบการณ์ระดับหนึ่ง (การสร้าง API สำหรับแอพและสำหรับ mvc) ส่วนใหญ่ฉันทำทั้งสองอย่าง

ฉันสร้างโปรเจ็กต์แยกต่างหากสำหรับการโทร api ที่มาจากไคลเอนต์อื่นหรืออุปกรณ์อื่น (แอพ Android / IOS) สาเหตุหนึ่งเป็นเพราะการรับรองความถูกต้องแตกต่างกันโดยเป็นแบบโทเค็น (เพื่อให้เป็นแบบไร้สัญชาติ) ฉันไม่ต้องการผสมสิ่งนี้ในแอปพลิเคชัน MVC ของฉัน

สำหรับ javascript / jquery api ของฉันเรียกใช้แอปพลิเคชัน mvc ของฉันฉันชอบที่จะทำให้สิ่งต่างๆเรียบง่ายดังนั้นฉันจึงรวม web api ไว้ในแอปพลิเคชัน MVC ของฉัน ฉันไม่ได้ตั้งใจที่จะมีการรับรองความถูกต้องโดยใช้โทเค็นด้วยการเรียก javascript api ของฉันเพราะเดี๋ยวก่อนมันอยู่ในแอปพลิเคชันเดียวกัน ฉันสามารถใช้[authorize]แอตทริบิวต์บนปลายทาง API ได้เมื่อผู้ใช้ไม่ได้เข้าสู่ระบบเขาจะไม่ได้รับข้อมูล

นอกจากนี้เมื่อจัดการกับตะกร้าสินค้าและคุณต้องการจัดเก็บตะกร้าสินค้าของผู้ใช้ในเซสชัน (ขณะที่ไม่ได้เข้าสู่ระบบ) คุณจะต้องมีสิ่งนี้ใน API ของคุณเช่นกันหากคุณเพิ่ม / ลบสินค้าผ่านรหัสจาวาสคริปต์ สิ่งนี้จะทำให้ API ของคุณมีสถานะอย่างแน่นอน แต่จะช่วยลดความซับซ้อนใน MVC-API ของคุณด้วย


4
@Dimi นั่นเป็นการแก้ไขที่ไร้ประโยชน์เพื่อให้ได้คะแนนเสียง ... ฉันจะปฏิเสธสิ่งเหล่านี้ได้อย่างไร?
CularBytes

ทำในสิ่งที่คุณต้องการ ฉันไม่ได้แก้ไขโดยการโหวต แต่เพื่อให้ดูดีที่สุดฉันคิดว่า ลุยเลย
DmitryBoyko

3
@CularBytes คุณไม่สามารถปฏิเสธการแก้ไขได้ แต่คุณสามารถแก้ไขได้อีกครั้งและย้อนกลับการเปลี่ยนแปลง สิ่งนี้ต้องใช้กระบวนการตรวจสอบโดยเพื่อนภายใต้ 2,000 ตัวแทน แต่คุณมีตัวแทนเพียงพอที่จะดำเนินการได้ทันที ฉันยอมรับว่าการแก้ไขไม่ได้เพิ่มมูลค่าใด ๆ และได้ย้อนกลับไปให้คุณแล้ว
Dan Bechard


5

เมื่อไม่นานมานี้ฉันได้ทำสิ่งเดียวกันเกือบทั้งหมด: ฉันเริ่มต้นด้วยโครงการแอปพลิเคชันเว็บ MVC 4 ใหม่โดยเลือกเทมเพลต Web API ใน VS2012

สิ่งนี้จะสร้าง Web API ที่โฮสต์ในแอปพลิเคชันเดียวกับ MVC

ฉันต้องการย้าย ApiControllers ไปไว้ในโปรเจ็กต์ไลบรารีคลาสแยกต่างหาก สิ่งนี้ค่อนข้างง่าย แต่วิธีแก้ปัญหานั้นซ่อนอยู่เล็กน้อย

ใน AssemblyInfo.cs ของโครงการ MVC 4 ให้เพิ่มบรรทัดรหัสที่คล้ายกัน

[assembly: PreApplicationStartMethod(typeof(LibraryRegistrator), "Register")]

ตอนนี้คุณต้องการคลาส LibraryRegistrator (อย่าลังเลที่จะตั้งชื่ออะไรก็ได้)

public class LibraryRegistrator
    {
        public static void Register()
        {
            BuildManager.AddReferencedAssembly(Assembly.LoadFrom(HostingEnvironment.MapPath("~/bin/yourown.dll")));
        }
    }

ในโครงการ MVC 4 ยังเพิ่มการอ้างอิงไปยังไลบรารี Api

ตอนนี้คุณสามารถเพิ่มตัวควบคุม Api ลงในไลบรารีคลาสแยกของคุณเอง (yourown.dll)


2

แม้ว่าโครงการของคุณจะซับซ้อนถึงขนาดต้องรับประกัน "ส่วนหน้า" สองรายการ แต่ฉันก็ยังคงพิจารณาแยก webapi ออกเป็นโครงการแยกต่างหากเป็นทางเลือกสุดท้าย คุณจะปวดหัวในการปรับใช้และคงเป็นเรื่องยากสำหรับมือใหม่ที่จะเข้าใจโครงสร้างของโซลูชันของคุณ ไม่ต้องพูดถึงปัญหาการกำหนดเส้นทาง

ฉันตั้งใจจะให้เนมสเปซ system.web แยกต่างหากใน "เลเยอร์การนำเสนอ" เดียว แม้ว่า webapi จะไม่ได้นำเสนอแต่ก็ยังคงเป็นส่วนหนึ่งของอินเทอร์เฟซของแอปพลิเคชันของคุณ ตราบใดที่คุณยังคงใช้ตรรกะในโดเมนของคุณและไม่ใช่ตัวควบคุมของคุณคุณก็ไม่ควรประสบปัญหามากเกินไป นอกจากนี้อย่าลืมใช้ประโยชน์จากพื้นที่


1
เหตุผลหลักของฉันในการต้องการโปรเจ็กต์แยกกันคือ API ไม่ใช่ส่วนหน้าจริงๆ เป็นชั้นกลาง
lordcheeto

6
"มันคงเป็นเรื่องยากสำหรับมือใหม่ที่จะเข้าใจ" ไม่ใช่เหตุผลที่ดีที่จะเลือกแนวทางใดแนวทางหนึ่ง ทำให้ง่ายเมื่อเป็นไปได้แน่นอน แต่ความต้องการที่ซับซ้อนมักต้องการการแก้ปัญหาที่ซับซ้อน แทนที่จะเขียนโค้ดโง่ ๆ เพื่อรองรับมือใหม่เราควรฝึกมือใหม่ให้เข้าใจและเขียนสมาร์ทโค้ด
Dan Bechard

0

นอกเหนือจากการตั้งค่า DLL แยกต่างหากสำหรับ Web.Api

เพียงคำแนะนำ:

  1. สร้างโครงการ
  2. นักเก็ต WebActivatorEx
  3. สร้าง aa class Method ที่จะเรียกใช้ app_start

    [แอสเซมบลี: WebActivatorEx.PostApplicationStartMethod (typeof (API.AppWebActivator), "Start")]

    [แอสเซมบลี: WebActivatorEx.ApplicationShutdownMethod (typeof (API.AppWebActivator), "Shutdown")]

  4. ลงทะเบียนเส้นทาง web.api ภายใน Start Method

    โมฆะคงที่สาธารณะ Start () {GlobalConfiguration.Configure (WebApiConfig.Register); }

  5. อ้างอิงโครงการไปยังโครงการเว็บ เพื่อเปิดใช้งานวิธีการเริ่มต้น

หวังว่านี่จะช่วยได้


0

ฉันพยายามแยกตัวควบคุม API ออกเป็นโปรเจ็กต์ใหม่ สิ่งที่ฉันทำคือสร้างโปรเจ็กต์ไลบรารีใหม่ย้ายคอนโทรลเลอร์ไปไว้ในโฟลเดอร์ชื่อ API จากนั้นเพิ่มการอ้างอิงของโครงการห้องสมุดในโครงการ MVC

การกำหนดค่า webAPI เหลืออยู่ในโครงการ MVC เอง มันทำงานได้ดี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.