ฉันเพิ่งค้นพบว่าทำไมเว็บไซต์ ASP.Net ทั้งหมดจึงช้าและฉันพยายามหาว่าจะทำอย่างไรกับมัน


275

ฉันเพิ่งค้นพบว่าทุกคำขอในเว็บแอปพลิเคชัน ASP.Net จะได้รับการล็อคเซสชันที่จุดเริ่มต้นของคำขอจากนั้นปล่อยเมื่อสิ้นสุดคำขอ!

ในกรณีที่ความหมายของสิ่งนี้หายไปกับคุณเช่นเดียวกับฉันในตอนแรกสิ่งนี้ก็หมายถึงสิ่งต่อไปนี้:

  • เมื่อใดก็ตามที่หน้าเว็บ ASP.Net ใช้เวลาโหลดนาน (อาจเป็นเพราะการโทรฐานข้อมูลที่ช้าหรืออะไรก็ตาม) และผู้ใช้ตัดสินใจว่าพวกเขาต้องการนำทางไปยังหน้าอื่นเพราะพวกเขาเบื่อที่จะรอพวกเขาไม่สามารถ! การล็อกเซสชัน ASP.Net บังคับให้มีการร้องขอหน้าใหม่เพื่อรอจนกว่าคำขอเดิมจะเสร็จสิ้นการโหลดช้าลงอย่างเจ็บปวด Arrrgh

  • เมื่อใดก็ตามที่ UpdatePanel โหลดช้าและผู้ใช้ตัดสินใจที่จะนำทางไปยังหน้าอื่นก่อนที่ UpdatePanel จะอัปเดตเสร็จสิ้น ... พวกเขาไม่สามารถ! การล็อคเซสชันของ ASP.net บังคับให้คำขอหน้าใหม่รอจนกว่าคำขอเดิมจะเสร็จสิ้นการโหลดช้าลงอย่างเจ็บปวด Double Arrrgh!

ดังนั้นตัวเลือกคืออะไร จนถึงตอนนี้ฉันก็เกิดขึ้นกับ:

  • ใช้ Custom SessionStateDataStore ซึ่ง ASP.Net รองรับ ฉันไม่ได้พบมากที่นั่นเพื่อคัดลอกและดูเหมือนว่ามีความเสี่ยงสูงและง่ายต่อการเลอะ
  • ติดตามคำขอทั้งหมดที่อยู่ระหว่างดำเนินการและหากมีคำขอมาจากผู้ใช้รายเดียวกันให้ยกเลิกคำขอเดิม ดูเหมือนจะสุดขีด แต่มันก็ใช้งานได้
  • อย่าใช้เซสชัน! เมื่อฉันต้องการสถานะบางอย่างสำหรับผู้ใช้ฉันก็สามารถใช้ Cache แทนและรายการสำคัญในชื่อผู้ใช้รับรองความถูกต้องหรือบางสิ่ง ดูเหมือนจะสุดโต่งอีกครั้ง

ฉันไม่อยากจะเชื่อเลยว่าทีม ASP.Net Microsoft จะทิ้งคอขวดที่มีประสิทธิภาพอย่างมากในเฟรมเวิร์กในเวอร์ชัน 4.0! ฉันขาดอะไรที่ชัดเจนหรือไม่ การใช้คอลเลกชัน ThreadSafe สำหรับเซสชันนั้นยากเพียงใด


40
คุณรู้ว่าเว็บไซต์นี้สร้างขึ้นบน. NET ที่กล่าวว่าฉันคิดว่ามันชั่งได้ค่อนข้างดี
ข้าวสาลี

7
ตกลงดังนั้นฉันจึงไม่ค่อยสนใจชื่อของฉัน ถึงกระนั้น IMHO ประสิทธิภาพการหนุนที่กำหนดออกจากการใช้งานกล่องของเซสชั่นจะเริ่มต้นที่น่าตกใจ นอกจากนี้ฉันคิดว่าพวก Stack Overflow ต้องทำ dev ที่กำหนดเองสูง ๆ เพื่อให้ได้ประสิทธิภาพและความสามารถในการปรับขนาดที่ทำได้ - และความรุ่งโรจน์ของพวกเขา สุดท้าย Stack Overflow เป็นแอป MVC ไม่ใช่ WebForms ซึ่งฉันเดิมพันช่วยได้ (แม้ว่าจะยอมรับว่านี่ยังใช้โครงสร้างพื้นฐานเซสชันเดียวกัน)
James


4
หาก Joel Mueller ให้ข้อมูลคุณเพื่อแก้ไขปัญหาของคุณทำไมคุณไม่ทำเครื่องหมายคำตอบของเขาว่าเป็นคำตอบที่ถูกต้องหรือไม่ แค่ความคิด
ars265

1
@ ars265 - Joel Muller ให้ข้อมูลที่ดีมากมายและฉันอยากจะขอบคุณเขาสำหรับสิ่งนั้น อย่างไรก็ตามในที่สุดฉันก็ไปด้วยเส้นทางที่แตกต่างจากที่แนะนำไว้ในโพสต์ของเขา ดังนั้นการทำเครื่องหมายโพสต์ที่แตกต่างกันเป็นคำตอบ
James

คำตอบ:


201

หากหน้าของคุณไม่ได้แก้ไขตัวแปรเซสชันใด ๆ คุณสามารถยกเลิกการล็อคส่วนใหญ่ได้

<% @Page EnableSessionState="ReadOnly" %>

หากหน้าของคุณไม่อ่านตัวแปรเซสชันใด ๆ คุณสามารถยกเลิกการล็อกนี้โดยสิ้นเชิงสำหรับหน้านั้น

<% @Page EnableSessionState="False" %>

หากหน้าใดของคุณไม่ใช้ตัวแปรเซสชันเพียงปิดสถานะเซสชันใน web.config

<sessionState mode="Off" />

ฉันอยากรู้คุณคิดว่า "คอลเลกชัน ThreadSafe" จะทำอย่างไรให้กลายเป็นเธรดที่ปลอดภัยถ้ามันไม่ได้ใช้ล็อค?

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

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


2
สวัสดี Joel ขอบคุณสำหรับเวลาในคำตอบนี้ นี่เป็นคำแนะนำที่ดีและอาหารสำหรับความคิด ฉันไม่เข้าใจการให้เหตุผลของคุณที่บอกว่าค่าทั้งหมดสำหรับเซสชันนั้นจะต้องถูกล็อคโดยเฉพาะกับคำขอทั้งหมด ค่า ASP.Net Cache สามารถเปลี่ยนแปลงได้ตลอดเวลาโดยเธรดใด ๆ เหตุใดจึงควรแตกต่างกันสำหรับเซสชัน ปัญหาเดียวที่ฉันมีกับตัวเลือกแบบอ่านอย่างเดียวคือหากผู้พัฒนาเพิ่มมูลค่าให้กับเซสชันเมื่อมันอยู่ในโหมดอ่านอย่างเดียวมันจะล้มเหลวอย่างเงียบ ๆ (ไม่มีข้อยกเว้น) ในความเป็นจริงมันเก็บค่าสำหรับส่วนที่เหลือของการร้องขอ - แต่ไม่เกิน
James

5
@James - ฉันแค่คาดเดาถึงแรงจูงใจของนักออกแบบที่นี่ แต่ฉันคิดว่ามันเป็นเรื่องธรรมดามากที่จะมีค่าหลายค่าขึ้นอยู่กับแต่ละคนในการใช้งานของผู้ใช้คนเดียวมากกว่าในแคช เหตุผลหน่วยความจำในเวลาใดก็ได้ หากหน้าหนึ่งตั้งค่าตัวแปรเซสชันที่เกี่ยวข้องกัน 4 รายการและอีกหน้าหนึ่งอ่านหลังจากมีการแก้ไขเพียงสองชุดนั่นอาจทำให้เกิดข้อบกพร่องที่ยากต่อการวินิจฉัยได้ง่าย ฉันคิดว่านักออกแบบเลือกที่จะดู "สถานะปัจจุบันของเซสชันของผู้ใช้" เป็นหน่วยเดียวสำหรับวัตถุประสงค์ในการล็อคด้วยเหตุผลดังกล่าว
Joel Mueller

2
ดังนั้นพัฒนาระบบที่มีความสำคัญกับนักเขียนโปรแกรมตัวหารร่วมที่ต่ำที่สุดที่ไม่สามารถคิดออกล็อคได้? มีวัตถุประสงค์เพื่อเปิดใช้งานเว็บฟาร์มที่แชร์ช่วงเวลาเก็บข้อมูลระหว่างอินสแตนซ์ IIS หรือไม่ คุณสามารถยกตัวอย่างของสิ่งที่คุณจะเก็บไว้ในตัวแปรเซสชันได้หรือไม่? ฉันไม่สามารถคิดอะไรได้เลย
Jason Goemaat

2
ใช่นี่คือหนึ่งในวัตถุประสงค์ ทบทวนสถานการณ์ต่าง ๆ เมื่อมีการปรับสมดุลภาระและความซ้ำซ้อนในโครงสร้างพื้นฐาน เมื่อผู้ใช้ทำงานบนเว็บเพจนั่นคือเขากำลังป้อนข้อมูลในรูปแบบสมมติว่า 5 นาทีและบางสิ่งบางอย่างใน webfarm ล่ม - powersource ของโหนดหนึ่งหายไป - ผู้ใช้ไม่ควรสังเกตว่า เขาไม่สามารถถูกเตะออกจากเซสชั่นเพียงเพราะเซสชั่นของเขาหายไปเพียงเพราะกระบวนการของผู้ปฏิบัติงานของเขาไม่ได้อยู่อีกต่อไป ซึ่งหมายความว่าในการจัดการสมดุลที่สมบูรณ์แบบ / ซ้ำซ้อนเซสชันจะต้องได้รับการส่งออกจากโหนดงาน ..
quetzalcoatl

6
อีกระดับที่มีประโยชน์ของการเลือกไม่ใช้อยู่<pages enableSessionState="ReadOnly" />ใน web.config และใช้ @Page เพื่อเปิดใช้งานการเขียนในหน้าเฉพาะเท่านั้น
MattW

84

ตกลงอุปกรณ์ประกอบฉากขนาดใหญ่สำหรับ Joel Muller สำหรับทุกสิ่งที่เขาป้อน ทางออกสุดท้ายของฉันคือการใช้ Custom SessionStateModule โดยละเอียดที่ส่วนท้ายของบทความ MSDN นี้:

http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx

นี้คือ:

  • ใช้งานได้รวดเร็วมาก (ดูเหมือนจะง่ายกว่าไปตามเส้นทางของผู้ให้บริการ)
  • ใช้เซสชัน ASP.Net มาตรฐานจำนวนมากในการจัดการนอกกรอบ (ผ่านคลาส SessionStateUtility)

สิ่งนี้สร้างความแตกต่างอย่างมากต่อความรู้สึกของ "ความยืดหยุ่น" ต่อแอปพลิเคชันของเรา ฉันยังไม่อยากเชื่อว่าการใช้งานที่กำหนดเองของ ASP.Net Session จะล็อคเซสชันสำหรับคำขอทั้งหมด นี่เป็นการเพิ่มความซบเซาในเว็บไซต์จำนวนมาก เมื่อพิจารณาจากจำนวนการวิจัยออนไลน์ที่ฉันต้องทำ (และการสนทนากับนักพัฒนา ASP.Net ที่มีประสบการณ์จริง ๆ หลายคน) ผู้คนจำนวนมากได้ประสบปัญหานี้ แต่มีคนเพียงไม่กี่คนที่เคยถึงจุดต่ำสุดของสาเหตุ บางทีฉันอาจจะเขียนจดหมายถึง Scott Gu ...

ฉันหวังว่านี่จะช่วยให้คนไม่กี่คนที่นั่น!


19
การอ้างอิงนั้นเป็นการค้นพบที่น่าสนใจ แต่ฉันต้องเตือนคุณเกี่ยวกับบางสิ่ง - รหัสตัวอย่างมีปัญหา: อันดับแรกReaderWriterLockเลิกใช้แล้วReaderWriterLockSlim- คุณควรใช้สิ่งนั้นแทน ข้อที่สองlock (typeof(...))เลิกใช้แล้ว - คุณควรล็อคแทนอินสแตนซ์วัตถุคงที่ส่วนตัวแทน ประการที่สามวลี "แอปพลิเคชันนี้ไม่ได้ป้องกันการร้องขอทางเว็บในเวลาเดียวกันจากการใช้ตัวระบุเซสชันเดียวกัน" เป็นการเตือนไม่ใช่คุณลักษณะ
Joel Mueller

3
ฉันคิดว่าคุณสามารถใช้งานได้ แต่คุณต้องแทนที่การใช้งานSessionStateItemCollectionในโค้ดตัวอย่างด้วยคลาสที่ปลอดภัยต่อเธรด (อาจขึ้นอยู่กับConcurrentDictionary) หากคุณต้องการหลีกเลี่ยงข้อผิดพลาดที่ยากต่อการทำซ้ำภายใต้โหลด
Joel Mueller

3
ฉันเพิ่งดูสิ่งนี้อีกเล็กน้อยและโชคไม่ดีที่ISessionStateItemCollectionต้องใช้Keysอสังหาริมทรัพย์ประเภทSystem.Collections.Specialized.NameObjectCollectionBase.KeysCollection- ซึ่งไม่มีสิ่งก่อสร้างสาธารณะ Gee ขอบคุณมาก สะดวกมาก
Joel Mueller

2
ตกลงฉันเชื่อว่าในที่สุดฉันก็มีการใช้งาน threadsafe แบบเต็มซึ่งไม่ใช่การล็อกการอ่านเพื่อใช้งานเซสชัน ขั้นตอนสุดท้ายเกี่ยวข้องกับการใช้คอลเลกชัน threadsafeate SessionStateItem ที่กำหนดเองซึ่งมีพื้นฐานมาจากบทความ MDSN ที่เชื่อมโยงกับความคิดเห็นด้านบน ชิ้นสุดท้ายของปริศนาที่มีนี้ถูกสร้างแจงนับด้ายบนพื้นฐานของบทความดีดีนี้: codeproject.com/KB/cs/safe_enumerable.aspx
James

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

31

ฉันเริ่มใช้AngiesList.Redis.RedisSessionStateModuleซึ่งนอกเหนือจากการใช้เซิร์ฟเวอร์ Redis (เร็วมาก) สำหรับการจัดเก็บ (ฉันใช้พอร์ต windows - แม้ว่าจะมีพอร์ต MSOpenTech ) แต่ก็ไม่ได้ล็อคเซสชันอย่างแน่นอน .

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

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


ลิงก์ GitHub ของคุณน่าจะเป็น 404 คน Libraries.io/github/angieslist/AL-Redisน่าจะเป็น URL ใหม่หรือไม่?
Uwe Keim

ดูเหมือนว่าผู้แต่งต้องการที่จะลบไลบรารี่ออกจากลิงค์ที่สอง ฉันจะลังเลที่จะใช้ห้องสมุดที่ถูกทอดทิ้ง แต่มีทางแยกที่นี่: github.com/PrintFleet/AL-Redisและห้องสมุดทางเลือกที่เชื่อมโยงจากที่นี่: stackoverflow.com/a/10979369/12534
Christian Davén

21

ฉันเตรียมห้องสมุดจากลิงก์ที่โพสต์ในกระทู้นี้ มันใช้ตัวอย่างจาก MSDN และ CodeProject ขอบคุณเจมส์

ฉันยังทำการแก้ไขตามคำแนะนำของ Joel Mueller

รหัสอยู่ที่นี่:

https://github.com/dermeister0/LockFreeSessionState

โมดูล HashTable:

Install-Package Heavysoft.LockFreeSessionState.HashTable

โมดูล ScaleOut StateServer:

Install-Package Heavysoft.LockFreeSessionState.Soss

โมดูลที่กำหนดเอง:

Install-Package Heavysoft.LockFreeSessionState.Common

หากคุณต้องการใช้การสนับสนุน Memcached หรือ Redis ให้ติดตั้งแพ็คเกจนี้ จากนั้นสืบทอดคลาสLockFreeSessionStateModuleและใช้เมธอด abstract

รหัสยังไม่ได้ทดสอบกับการผลิต ยังต้องปรับปรุงการจัดการข้อผิดพลาด ข้อยกเว้นจะไม่ติดอยู่ในการใช้งานปัจจุบัน

ผู้ให้บริการเซสชันที่ไม่มีการล็อคโดยใช้ Redis:


มันต้องการไลบรารี่จากโซลูชัน ScaleOut ซึ่งไม่ว่างใช่ไหม
Hoàng Long

1
ใช่ฉันสร้างการใช้งานสำหรับ SOSS เท่านั้น คุณสามารถใช้ผู้ให้บริการเซสชัน Redis ที่กล่าวถึงได้ฟรี
Der_Meister

บางทีHoàng Long พลาดจุดที่คุณมีตัวเลือกระหว่างการใช้งาน HashTable ในหน่วยความจำและ ScaleOut StateServer
David De Sloovere

ขอบคุณสำหรับการบริจาคของคุณ :) ฉันจะลองดูว่ามันจะทำงานอย่างไรในบางกรณีที่เรามีกับ SESSION ที่เกี่ยวข้อง
Agustin Garzon

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

11

ฉันคิดว่าคุณมี 2 แนวทาง:

  1. อย่าใช้เซสชันเลย
  2. ใช้เซสชั่นตามที่เป็นอยู่และทำการปรับจูนตามที่โจเอลพูด

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

คุณสามารถสร้างเซสชันเช่นพฤติกรรมได้หลายวิธี แต่ถ้าไม่ล็อคเซสชันปัจจุบันจะไม่เป็น 'เซสชัน'

สำหรับปัญหาเฉพาะที่คุณกล่าวถึงผมคิดว่าคุณควรตรวจสอบHttpContext.Current.Response.IsClientConnected สิ่งนี้มีประโยชน์ในการป้องกันการประมวลผลที่ไม่จำเป็นและรอลูกค้าแม้ว่าจะไม่สามารถแก้ปัญหานี้ได้ทั้งหมดเนื่องจากสามารถใช้โดยวิธีการรวมกำไรเท่านั้นไม่ใช่ async


10

หากคุณใช้การอัปเดตMicrosoft.Web.RedisSessionStateProvider(เริ่มต้นจาก3.0.2) คุณสามารถเพิ่มสิ่งนี้ลงในของคุณweb.configเพื่ออนุญาตเซสชันที่เกิดขึ้นพร้อมกัน

<appSettings>
    <add key="aspnet:AllowConcurrentRequestsPerSession" value="true"/>
</appSettings>

แหล่ง


ไม่แน่ใจว่าทำไมถึงเกิดขึ้นที่ 0. +1 มีประโยชน์มาก.
Pangamma

สิ่งนี้ใช้งานได้ในแอพโหมดคลาสสิกหรือไม่ github.com/Azure/aspnet-redis-providers/issues/123
Rusty

สิ่งนี้ใช้ได้กับผู้ให้บริการรัฐ inProc หรือเซสชันเริ่มต้นหรือไม่
Nick Chan Abdullah

โปรดทราบว่าโปสเตอร์อ้างอิงหากคุณใช้ RedisSessionStateprovider แต่อาจทำงานกับผู้ให้บริการ AspNetSessionState Async รุ่นใหม่เหล่านี้ (สำหรับ SQL และ Cosmos) เพราะอยู่ในเอกสารประกอบ: github.com/aspnet/AspNetSessionStateฉันเดาว่ามันจะทำงานใน โหมดคลาสสิคถ้า SessionStateProvider ทำงานในโหมดคลาสสิคอยู่แล้วน่าจะเกิดสิ่งที่สถานะเซสชันเกิดขึ้นภายใน ASP.Net (ไม่ใช่ IIS) ด้วย InProc มันอาจไม่ทำงาน แต่จะมีปัญหาน้อยลงเพราะมันแก้ปัญหาการแย่งชิงทรัพยากรซึ่งเป็นข้อตกลงที่ใหญ่กว่าจากสถานการณ์ของ proc
madamission

4

สำหรับ ASPNET MVC เราทำสิ่งต่อไปนี้:

  1. ตามค่าเริ่มต้นให้ตั้งค่าSessionStateBehavior.ReadOnlyการดำเนินการของคอนโทรลเลอร์ทั้งหมดโดยลบล้างDefaultControllerFactory
  2. ในการดำเนินการของตัวควบคุมที่จำเป็นต้องมีการเขียนไปยังสถานะเซสชันทำเครื่องหมายด้วยแอตทริบิวต์เพื่อตั้งค่า SessionStateBehavior.Required

สร้าง ControllerFactory GetControllerSessionBehaviorที่กำหนดเองและแทนที่

    protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
    {
        var DefaultSessionStateBehaviour = SessionStateBehaviour.ReadOnly;

        if (controllerType == null)
            return DefaultSessionStateBehaviour;

        var isRequireSessionWrite =
            controllerType.GetCustomAttributes<AcquireSessionLock>(inherit: true).FirstOrDefault() != null;

        if (isRequireSessionWrite)
            return SessionStateBehavior.Required;

        var actionName = requestContext.RouteData.Values["action"].ToString();
        MethodInfo actionMethodInfo;

        try
        {
            actionMethodInfo = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        }
        catch (AmbiguousMatchException)
        {
            var httpRequestTypeAttr = GetHttpRequestTypeAttr(requestContext.HttpContext.Request.HttpMethod);

            actionMethodInfo =
                controllerType.GetMethods().FirstOrDefault(
                    mi => mi.Name.Equals(actionName, StringComparison.CurrentCultureIgnoreCase) && mi.GetCustomAttributes(httpRequestTypeAttr, false).Length > 0);
        }

        if (actionMethodInfo == null)
            return DefaultSessionStateBehaviour;

        isRequireSessionWrite = actionMethodInfo.GetCustomAttributes<AcquireSessionLock>(inherit: false).FirstOrDefault() != null;

         return isRequireSessionWrite ? SessionStateBehavior.Required : DefaultSessionStateBehaviour;
    }

    private static Type GetHttpRequestTypeAttr(string httpMethod) 
    {
        switch (httpMethod)
        {
            case "GET":
                return typeof(HttpGetAttribute);
            case "POST":
                return typeof(HttpPostAttribute);
            case "PUT":
                return typeof(HttpPutAttribute);
            case "DELETE":
                return typeof(HttpDeleteAttribute);
            case "HEAD":
                return typeof(HttpHeadAttribute);
            case "PATCH":
                return typeof(HttpPatchAttribute);
            case "OPTIONS":
                return typeof(HttpOptionsAttribute);
        }

        throw new NotSupportedException("unable to determine http method");
    }

AcquireSessionLockAttribute

[AttributeUsage(AttributeTargets.Method)]
public sealed class AcquireSessionLock : Attribute
{ }

เชื่อมต่อโรงงานควบคุมที่สร้างขึ้นมา global.asax.cs

ControllerBuilder.Current.SetControllerFactory(typeof(DefaultReadOnlySessionStateControllerFactory));

ตอนนี้เราสามารถมีทั้งread-onlyและภาครัฐในครั้งเดียวread-writeController

public class TestController : Controller 
{
    [AcquireSessionLock]
    public ActionResult WriteSession()
    {
        var timeNow = DateTimeOffset.UtcNow.ToString();
        Session["key"] = timeNow;
        return Json(timeNow, JsonRequestBehavior.AllowGet);
    }

    public ActionResult ReadSession()
    {
        var timeNow = Session["key"];
        return Json(timeNow ?? "empty", JsonRequestBehavior.AllowGet);
    }
}

หมายเหตุ: สถานะเซสชัน ASPNET ยังคงสามารถเขียนได้แม้ในโหมดอ่านอย่างเดียวและจะไม่ทิ้งข้อยกเว้นในรูปแบบใด ๆ (มันไม่ล็อคเพื่อรับประกันความมั่นคง) ดังนั้นเราจึงต้องระมัดระวังในการทำเครื่องหมาย AcquireSessionLockในการกระทำของตัวควบคุมที่ต้องเขียนสถานะเซสชัน



3

การทำเครื่องหมายสถานะเซสชันของคอนโทรลเลอร์เป็นแบบอ่านอย่างเดียวหรือปิดใช้งานจะช่วยแก้ปัญหาได้

คุณสามารถตกแต่งคอนโทรลเลอร์ด้วยแอ็ตทริบิวต์ต่อไปนี้เพื่อทำเครื่องหมายเป็นอ่านอย่างเดียว:

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

System.Web.SessionState.SessionStateBehavior enum มีค่าต่อไปนี้:

  • ค่าเริ่มต้น
  • พิการ
  • อ่านเท่านั้น
  • จำเป็นต้องใช้

0

เพียงเพื่อช่วยให้ทุกคนที่มีปัญหานี้ (ล็อคคำขอเมื่อดำเนินการอีกคนหนึ่งจากเซสชั่นเดียวกัน) ...

วันนี้ฉันเริ่มที่จะแก้ปัญหานี้และหลังจากการวิจัยเป็นเวลาหลายชั่วโมงฉันแก้ไขได้โดยลบSession_Startวิธีการ (แม้ว่าจะว่างเปล่า) ออกจากGlobal.asaxไฟล์

ใช้ได้กับทุกโครงการที่ฉันทดสอบ


IDK เป็นโครงการประเภทใด แต่เหมืองของฉันไม่มีSession_Startวิธีการและยังคงล็อค
Denis G. Labrecque

0

หลังจากดิ้นรนกับตัวเลือกที่มีทั้งหมดฉันลงเอยด้วยการเขียนผู้ให้บริการ SessionStore โดยใช้โทเค็น JWT (เซสชันเดินทางภายในคุกกี้และไม่จำเป็นต้องใช้ที่เก็บข้อมูลส่วนหลัง)

http://www.drupalonwindows.com/en/content/token-sessionstate

ข้อดี:

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