จะเข้าถึงเมธอด HttpServerUtility.MapPath ใน Thread หรือ Timer ได้อย่างไร?


89

ฉันใช้System.Timers.Timerแอปพลิเคชัน Asp.Net ของฉันและฉันจำเป็นต้องใช้HttpServerUtility.MapPathวิธีการที่ดูเหมือนว่าจะใช้ได้ผ่านทางHttpContext.Current.Server.MapPathไฟล์. ปัญหาคือว่าHttpContext.Currentคือnullเมื่อTimer.Elapsedเหตุการณ์ fires

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

ขอบคุณ!

คำตอบ:


143

เป็นไปได้ที่จะใช้HostingEnvironment.MapPath()แทนHttpContext.Current.Server.MapPath()

ฉันยังไม่ได้ลองในเธรดหรือเหตุการณ์ตัวจับเวลา


ฉันพิจารณาวิธีแก้ปัญหาบางอย่าง (ใช้ไม่ได้)

  • วิธีเดียวที่ฉันดูแลเกี่ยวกับเกี่ยวกับการมีHttpServerUtility MapPathเพื่อเป็นทางเลือกหนึ่งที่ฉันสามารถใช้AppDomain.CurrentDomain.BaseDirectoryและสร้างเส้นทางจากสิ่งนี้ แต่จะล้มเหลวหากแอปของคุณใช้ไดเรกทอรีเสมือน (Mine does)

  • แนวทางอื่น: เพิ่มเส้นทางทั้งหมดที่ฉันต้องการในGlobalชั้นเรียน Application_Startแก้ไขเส้นทางเหล่านี้ใน


1
อย่างไรก็ตามโปรดทราบว่าข้างต้นใช้ไม่ได้กับ IIS เวอร์ชันที่ใหม่กว่า ใน IIS7 แอปพลิเคชันเริ่มต้นอาจถูกเรียกนอกคำขอ http นั่นคือตัวอย่างโค้ด ฉันแน่ใจว่า HostingEnvironment.MapPath () จะยังคงใช้งานได้เหมือนเดิม
Robba

แต่ HostingEnvironment.MapPath () ให้ข้อผิดพลาดหากคุณส่งผ่านและสตริงว่างเปล่าเพื่อรับเส้นทางโฟลเดอร์โดยตรง ... HttpContext.Current.Server.MapPath (""); -> ทำงาน HostingEnvironment.MapPath (""); -> ทำให้เกิดข้อผิดพลาด
VSP

14

ฉันไม่รู้ว่าวิธีนี้จะช่วยแก้ปัญหาไดเรกทอรีเสมือนของคุณได้หรือไม่ แต่ฉันใช้สำหรับ MapPath:

public static string MapPath(string path)
{
    if (HttpContext.Current != null)
        return HttpContext.Current.Server.MapPath(path);

    return HttpRuntime.AppDomainAppPath + path.Replace("~", string.Empty).Replace('/', '\\');
}

path.Replace ("~", string.Empty) ควรเป็น path.Replace ('~', '.')
Slava

13

HostingEnvironment ไม่ใช่โซลูชันที่สมบูรณ์แบบเนื่องจากเป็นคลาสที่ยากมากที่จะเยาะเย้ย (ดูวิธีการทดสอบรหัสหน่วยที่ใช้ HostingEnvironment.MapPath )

สำหรับผู้ที่ต้องการความสามารถในการทดสอบวิธีที่ดีกว่าคือการสร้างอินเทอร์เฟซ path-mapper ของคุณเองตามที่เสนอโดยhttps://stackoverflow.com/a/1231962/85196ยกเว้นใช้เป็น

public class ServerPathMapper : IPathMapper { 
 public string MapPath(string relativePath) { 
      return HostingEnvironment.MapPath(relativePath); 
 } 
} 

ผลลัพธ์นั้นสามารถล้อเลียนได้อย่างง่ายดายใช้ HostingEnvironment ภายในและยังสามารถจัดการกับข้อกังวลของ ase69s ได้ในเวลาเดียวกัน


สิ่งนี้ทำให้ฉันสามารถจัดเตรียมการใช้งานสำหรับการแก้ปัญหาเส้นทางสำหรับโครงการ Web API โดยไม่ต้องพึ่งพา System.Web หรือ System.Net ในไลบรารีที่อ้างถึง +1
David Peterson

ยกนิ้วให้ DI และความสามารถในการทดสอบของแนวทางนี้
Dilhan Jayathilake

2

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


2

เมื่อเวลาผ่านไปไม่มีบริบท HTTP ปัจจุบัน เนื่องจากเหตุการณ์ตัวจับเวลาไม่เกี่ยวข้องกับคำขอ HTTP เฉพาะ

สิ่งที่คุณควรทำคือใช้ HttpServerUtility.MapPath ที่มีบริบท HTTP คุณสามารถทำได้ในเหตุการณ์ไปป์ไลน์คำขอ (เช่น Page_Load) หรือในเหตุการณ์ Global.asax เช่น Application_Start

กำหนดผลลัพธ์ MapPath ให้กับตัวแปรที่เข้าถึงได้จาก Timer.Elapsed event ซึ่งคุณสามารถใช้ Path.Combine เพื่อรับตำแหน่งของไฟล์เฉพาะที่คุณต้องการ


0

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

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