อักขระจุด '.' ใน MVC Web API 2 สำหรับคำขอเช่น api / people / STAFF.45287


107

URL ที่ฉันพยายามให้ทำงานเป็นหนึ่งในรูปแบบของ: http://somedomain.com/api/people/staff.33311 (เช่นเดียวกับไซต์เช่น LAST.FM อนุญาตให้มีสัญญาณทุกประเภทใน URL RESTFul & WebPage ตัวอย่างเช่น " http://www.last.fm/artist/psy'aviah " เป็น URL ที่ถูกต้องสำหรับ LAST.FM)

สถานการณ์ต่อไปนี้ทำงานอะไร: - http://somedomain.com/api/people/ - ซึ่งส่งคืนทุกคน - http://somedomain.com/api/people/staff33311 - จะใช้ได้เช่นกัน แต่ไม่ใช่สิ่งที่ฉัน ' หลังจากนั้นฉันต้องการให้ URL ยอมรับ "จุด" ดังตัวอย่างด้านล่าง - http://somedomain.com/api/people/staff.33311 - แต่สิ่งนี้ทำให้ฉันมี

HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

ฉันได้ตั้งค่าสิ่งต่อไปนี้:

  1. ตัวควบคุม "PeopleController"

    public IEnumerable<Person> GetAllPeople()
    {
        return _people;
    }
    
    public IHttpActionResult GetPerson(string id)
    {
        var person = _people.FirstOrDefault(p => p.Id.ToLower().Equals(id.ToLower()));
        if (person == null)
            return NotFound();
    
        return Ok(person);
    }    
  2. WebApiConfig.cs

    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
    
        // Web API routes
        config.MapHttpAttributeRoutes();
    
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }

ฉันได้ลองทำตามคำแนะนำทั้งหมดของบล็อกโพสต์นี้แล้วhttp://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspxแต่ก็ยังใช้ไม่ได้ฉันคิดว่ามันค่อนข้างน่าเบื่อและฉันสงสัยว่าจะไม่มีอีกหรือไม่ วิธีที่ดีและปลอดภัยยิ่งขึ้น

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


10
ไม่ใช่คำตอบ แต่เป็นสาเหตุที่คุณได้รับ 404 สำหรับsomedomain.com/api/people/staff.33311โดยค่าเริ่มต้น IIS จะดู URL นี้และเห็นไฟล์. เป็นนามสกุลไฟล์และเรียกใช้ตัวจัดการไฟล์แบบคงที่โดยข้าม MVC API ของคุณ คำตอบที่คุณยอมรับ (เรียกใช้โมดูลที่มีการจัดการทั้งหมดสำหรับคำขอทั้งหมด) ทำงานได้เนื่องจากคุณบังคับให้ทุกคำขอไปยัง IIS ผ่านไปป์ไลน์ ASP.NET (ดังนั้นคอนโทรลเลอร์ของคุณ)
Henry C

โพสต์ที่เกี่ยวข้องอย่างใกล้ชิดที่นี่
RBT

คำตอบ:


105

การตั้งค่าต่อไปนี้ในweb.configไฟล์ของคุณควรแก้ไขปัญหาของคุณ:

<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />

4
มันทำเคล็ดลับ แม้ว่าการตั้งค่าตัวเลือกนี้จะมีช่องโหว่หรือไม่ เหตุใดจึงไม่เป็นพฤติกรรมมาตรฐาน
Yves Schelpe

2
โอเคสำหรับทุกคนที่สนใจ: ฉันเห็นว่าคำถามของฉันด้านบนมีคำตอบอยู่ที่นี่เกี่ยวกับคำตอบที่ยอมรับในขณะที่เขียน (คำตอบโดย Kapil Khandelwal): stackoverflow.com/questions/11048863/…
Yves Schelpe

2
ใช่มันใช้งานได้บัสอื่น ๆ ฉันต้องการทราบว่าจำเป็นต้องใช้โมดูลใดเพื่อให้ฟังก์ชันนี้ทำงานได้?
Greg Z.

3
เมื่อฉันลองสิ่งนี้มันจะใช้ได้ก็ต่อเมื่อฉันใส่ '/' ที่ท้ายเส้นทาง มีข้อเสนอแนะว่าทำไมถึงเป็นเช่นนี้? ในหมายเหตุด้านข้างคำตอบด้านล่างที่เพิ่ม 'UrlRoutingModule' โดยเฉพาะแทนที่จะเรียกใช้โมดูลทั้งหมดก็ใช้ได้ผลสำหรับฉันเช่นกันแม้ว่าจะยังคงมีปัญหาที่ต้องใช้ '/' ในตอนท้ายถึงจะทำงานได้
Nikolaj Dam Larsen

10
stackoverflow.com/a/12151501/167018คุ้มค่าที่จะดูว่าคุณกังวล (และถูกต้องเช่นนั้น) เกี่ยวกับผลกระทบด้านประสิทธิภาพของการเปิดใช้งาน runAllManagedModulesForAllRequests
Henry C

140

ต่อท้าย URL ด้วยเครื่องหมายทับเช่นhttp://somedomain.com/api/people/staff.33311/แทนhttp://somedomain.com/api/people/staff.33311.


3
@AgustinMeriles คำตอบของฉันอาจถือได้ว่าเป็นวิธีแก้ปัญหามากกว่าคำตอบจริงขึ้นอยู่กับการตีความคำถามของคุณ
Danny Varod

5
วิธีนี้ใช้ไม่ได้แม้ว่าจุดจะอยู่ท้ายส่วน URL ในรูป / people / member
eYe

2
ไม่ถ้าฉันไม่ต้องการเฉือนตอนจบล่ะ?! ไม่ควรจำเป็น
Josh M.

1
@ จอช. นี่เป็นวิธีแก้ปัญหาฉันไม่ได้เขียน ASP.NET นอกจากนี้เครื่องหมายทับจะไม่ส่งผลต่อคำขอ มันไม่ แต่ช่วยทำให้ความตั้งใจของคุณชัดเจนมากขึ้นในขณะที่เมื่อเทียบกับgoogle.com/my query goes here/ google.com/subDomain my query goes here
Danny Varod

1
ใช่นี่เป็นวิธีที่ดีที่สุดที่คุณไม่ควรต้องแก้ไข web.config
Timothy Gonzalez

35

ฉันพบว่าการเพิ่มสิ่งต่อไปนี้ก่อนมาตรฐานExtensionlessUrlHandlerจะช่วยแก้ปัญหาให้ฉันได้:

<add name="ExtensionlessUrlHandler-Integrated-4.0-ForApi"
     path="api/*"
     verb="*"
     type="System.Web.Handlers.TransferRequestHandler"
     preCondition="integratedMode,runtimeVersionv4.0" />

ฉันไม่คิดว่าชื่อมีความสำคัญมากขนาดนั้นยกเว้นว่าอาจช่วยได้หาก IDE ของคุณ (Visual Studio ในกรณีของฉัน) จัดการการกำหนดค่าไซต์ของคุณ

H / T ไปที่https://stackoverflow.com/a/15802305/264628


ฉันเพิ่มมัน 'หลัง' บรรทัดมาตรฐานและมันก็ใช้ได้ดีเช่นกัน
Jalal El-Shaer

นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ไม่ต้องใช้ / ท้าย uri
daudihus

2
ขอบคุณสำหรับก่อนเพราะมันใช้งานไม่ได้!
Mese

ฉันเชื่อว่าโมดูลทำงานตามลำดับการประกาศดังนั้นควรใส่โมดูลที่เฉพาะเจาะจง (หรือสำคัญกว่า) ไว้ก่อนโมดูลทั่วไป
BrianS

24

ฉันไม่รู้ว่าฉันกำลังทำอะไรอยู่ แต่หลังจากเล่นกับคำตอบก่อนหน้านี้เล็กน้อยฉันก็หาวิธีแก้ปัญหาอื่นที่อาจเหมาะสมกว่า:

<system.webServer>
<modules>
    <remove name="UrlRoutingModule-4.0" />
    <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
</modules>
</system.webServer>

ขอบคุณฉันยังไม่รู้ว่ามันกำลังทำอะไร แต่ดูดีกว่าวิธีแก้ปัญหาอื่น ๆ
Thomas

1
ดูเหมือนจะย้ายโมดูลการกำหนดเส้นทาง url (ซึ่งเป็นสิ่งที่จับได้ว่าคำขอมีส่วนขยายและพยายามจัดการเป็นไฟล์) ไปยังส่วนท้ายของรายการโมดูลซึ่งเพียงพอที่จะวางไว้หลังจากโมดูลที่จัดการคำขอ api . IMHO นี่เป็นวิธีแก้ปัญหาที่ดีที่สุดจากที่ฉันเคยเห็นใน SO อย่างน้อยATTOW
James Manning

1
ไม่ใช่การย้ายตำแหน่งไปยังส่วนท้ายของรายการ แต่เป็นการลบเงื่อนไขเบื้องต้นเริ่มต้นที่โมดูลนี้เรียกใช้สำหรับตัวจัดการที่มีการจัดการเท่านั้น การกำหนดค่าเริ่มต้นใช้รูปแบบนี้:<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler" />
theta-fish

ขอบคุณ - ที่จะอธิบายพฤติกรรม
Greg Z

8

ฉันพบว่าฉันต้องทำมากกว่าเพียงแค่ตั้งค่าแอตทริบิวต์runAllManagedModulesForAllRequests trueฉันต้องตรวจสอบให้แน่ใจด้วยว่าตัวจัดการ URL ที่ไม่มีส่วนขยายได้รับการกำหนดค่าให้ดูทุกเส้นทาง นอกจากนี้ยังมีการตั้งค่าโบนัสอีกหนึ่งรายการที่คุณสามารถเพิ่มได้ซึ่งจะช่วยได้ในบางกรณี นี่คือ Web.config ที่ใช้งานได้ของฉัน:

<system.web>
    <httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <handlers>
        <remove name="WebDAV" />
        <remove name="OPTIONSVerbHandler" />
        <remove name="ExtensionlessUrlHandler-Integrated-4.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>

หมายเหตุเฉพาะที่ExtensionlessUrlHandler-Integrated-4.0มีของpathชุดแอตทริบิวต์*เมื่อเทียบกับ*.(ตัวอย่างเช่น)


ฉันเพิ่งได้รับบิตโดยpath="*.". แค่อยากรู้เหตุผลที่ผู้คนตั้งไว้path="*."คืออะไร?
JustinP8

อันที่จริงฉันเปลี่ยนเป็นpath="*"และมีปัญหาเนื่องจากเรากำลังโฮสต์ไซต์เอกสารเคียงข้างกับ WebAPI ของเราและไซต์นั้นมีปัญหากับ. jpg, .png และไฟล์อื่น ๆ ที่มีนามสกุล
JustinP8

@ JustinP8 ตั้งด้วย<modules runAllManagedModulesForAllRequests="true" />รึเปล่า? นั่นควรทำให้. NET จัดการกับไฟล์คงที่เหล่านั้น
Josh M.

1
ใช่. ฉันทำแบบนั้น ฉันไม่ชอบแบบนั้นจริงๆเพราะตอนนี้ไฟล์คงที่ทั้งหมดผ่านไปป์ไลน์. NET โชคดีที่นี่เป็นบริการ webAPI จึงมีผลกระทบเฉพาะส่วน Swagger และ Swashbuckle สำหรับไซต์เอกสาร / ตัวช่วย API เท่านั้นที่ได้รับผลกระทบ
JustinP8

ฉันพบว่าสิ่งนี้ทำให้คำขอไฟล์คงที่ทั้งหมดไม่สมบูรณ์ ข้อผิดพลาด 500 ฉันได้ runAllManaged ... ตั้งค่าเป็น true
แซม

2

ฉันติดอยู่ในสถานการณ์นี้ แต่การต่อ/ ท้าย URL ดูไม่สะอาดสำหรับฉัน

ดังนั้นเพียงเพิ่มด้านล่างในแท็กweb.config handlersและคุณจะดีไป

<add name="Nancy" path="api" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" allowPathInfo="true" />

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

1

ฉันพบว่าทั้งสองวิธีใช้ได้กับฉัน: การตั้งค่า runAllManagedModulesForAllRequests เป็น true หรือเพิ่ม ExtentionlessUrlHandler ดังต่อไปนี้ สุดท้ายฉันเลือกที่จะเพิ่ม extensionUrLHandler เนื่องจาก runAllManagedModulesForAllRequests มีผลกระทบต่อประสิทธิภาพกับไซต์

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" 
       type="System.Web.Handlers.TransferRequestHandler" 
       preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

1

ฉันจะใช้สิ่งนี้ในไฟล์ Web.config:

<add name="ManagedSpecialNames" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

ก่อนมาตรฐาน "ExtensionlessUrlHandler"

ตัวอย่างเช่นในกรณีของฉันฉันใส่ไว้ที่นี่:

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ManagedFiles" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

ดังนั้นคุณจึงบังคับให้คุณจัดการ URL ของรูปแบบดังกล่าวแทนที่จะเป็นการจัดการมาตรฐานเป็นไฟล์ในแผนผังไดเรกทอรีแอปพลิเคชัน


0

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

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

public class GetuserdetailsbyuseridController : ApiController
{
     string getuserdetailsbyuserid(string userId)
     {
        //some code to get user details
     }
}

ดู URL ด้านล่างที่ผู้ใช้ป้อนรหัสผู้ใช้เพื่อรับรายละเอียดส่วนตัวของเขา:

http://mywebsite:8080/getuserdetailsbyuserid/foo.bar

เนื่องจากคุณต้องดึงข้อมูลบางส่วนจากเซิร์ฟเวอร์เราจึงใช้GETคำกริยาhttp ในขณะที่ใช้การGETเรียกพารามิเตอร์อินพุตใด ๆ สามารถส่งผ่านได้ในส่วนของ URL เท่านั้น

ดังนั้นเพื่อแก้ปัญหาของฉันฉันเปลี่ยน http POSTกริยาของการกระทำของฉันไป POSTคำกริยาHttp มีความสะดวกในการส่งผ่านข้อมูลของผู้ใช้หรือผู้ใช้ที่ไม่ใช่ผู้ใช้ในร่างกายด้วย ดังนั้นฉันจึงสร้างข้อมูล JSON และส่งต่อไปยังเนื้อหาของPOSTคำขอhttp :

{
  "userid" : "foo.bar"
}

เปลี่ยนนิยามวิธีการของคุณดังต่อไปนี้:

public class GetuserdetailsbyuseridController : ApiController
{
     [Post]
     string getuserdetailsbyuserid([FromBody] string userId)
     {
        //some code to get user details
     }
}

หมายเหตุ : เมื่อเพิ่มเติมเกี่ยวกับการใช้GETคำกริยาและเมื่อใช้POSTคำกริยาที่นี่


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