มีวิธีบังคับให้ ASP.NET Web API ส่งคืนข้อความธรรมดาหรือไม่?


125

ฉันต้องการได้รับการตอบกลับเป็นข้อความธรรมดาจากตัวควบคุม ASP.NET Web API

ฉันได้ลองทำตามคำขอAccept: text/plainแต่ดูเหมือนจะไม่ได้ผล นอกจากนี้คำขอยังอยู่ภายนอกและอยู่นอกเหนือการควบคุมของฉัน สิ่งที่ฉันจะทำได้คือเลียนแบบวิธี ASP.NET แบบเก่า:

context.Response.ContentType = "text/plain";
context.Response.Write("some text);

ความคิดใด ๆ ?

แก้ไขวิธีแก้ปัญหา : จากคำตอบของ Aliostad ฉันได้เพิ่มตัวจัดรูปแบบข้อความWebAPIContribเริ่มต้นใน Application_Start:

  config.Formatters.Add(new PlainTextFormatter());

และคอนโทรลเลอร์ของฉันลงเอยด้วยสิ่งที่ชอบ:

[HttpGet, HttpPost]
public HttpResponseMessage GetPlainText()
{
  return ControllerContext.Request.CreateResponse(HttpStatusCode.OK, "Test data", "text/plain");
}

คำตอบ:


231

อืม ... ฉันไม่คิดว่าคุณจะต้องสร้างฟอร์แมตเตอร์แบบกำหนดเองเพื่อให้ทำงานนี้ได้ กลับเนื้อหาเช่นนี้แทน:

    [HttpGet]
    public HttpResponseMessage HelloWorld()
    {
        string result = "Hello world! Time is: " + DateTime.Now;
        var resp = new HttpResponseMessage(HttpStatusCode.OK);
        resp.Content = new StringContent(result, System.Text.Encoding.UTF8, "text/plain");
        return resp;
    }

สิ่งนี้ใช้ได้กับฉันโดยไม่ต้องใช้ฟอร์แมตเตอร์ที่กำหนดเอง

หากคุณต้องการสร้างเอาต์พุตอย่างชัดเจนและลบล้างการต่อรองเนื้อหาเริ่มต้นตามส่วนหัวยอมรับคุณจะไม่ต้องการใช้Request.CreateResponse()เพราะมันบังคับประเภท mime

แทนที่จะสร้างใหม่อย่างชัดเจนHttpResponseMessageและกำหนดเนื้อหาด้วยตนเอง ตัวอย่างข้างต้นใช้StringContentแต่มีคลาสเนื้อหาอื่น ๆ อีกไม่กี่คลาสที่สามารถส่งคืนข้อมูลจากชนิด / โครงสร้างข้อมูล. NET ต่างๆ


1
นี่เป็นวิธีแก้ปัญหาที่ฉันใช้เพราะ API ของฉันจะส่งคืนอ็อบเจ็กต์ JSON เป็น 99% ของวิธีการทั้งหมดมีเพียงไม่กี่วิธี (น้อยมาก) ที่ต้องการการตอบสนองแบบสตริงธรรมดา (และสำหรับหลาย ๆ วิธีที่ฉันใช้ MemoryStream เพื่อส่งคืนข้อมูล โดยตรงในการตอบสนองดังนั้นจึงไม่ใช่ปัญหา) ฉันส่งคืนสตริง. NET เพียง 2 หรือ 3 วิธีเท่านั้นและกำลังส่งคืนเป็นสตริง JSON คำตอบของคุณ IMHO คือการตอบกลับ KISS สำหรับปัญหานี้ (แม้ว่าจะไม่แห้ง 100% แต่ฉันเพิ่งเขียนวิธีการขยายเป็นสตริงเพื่อทำเช่นนั้น ... :-) ดี!) StringContent ดีมาก ขอบคุณ.
Loudenvier

มีคลาส XXXContent ที่กำหนดเองจำนวนมากเพื่อสร้างเนื้อหาประเภทเฉพาะที่ทำให้สิ่งเหล่านี้ตรงไปตรงมา
Rick Strahl

ฉันเห็นคำตอบที่ถูกต้องสำหรับแนวทางนี้ อย่างไรก็ตาม HttpContext.Current เป็นโมฆะในขณะนี้ มีความคิดเกี่ยวกับเรื่องนี้ไหม
Nachiket Mehta

@JavascriptEnthusiast - HttpContext ปัจจุบันเป็นโมฆะมากที่สุดเนื่องจากคุณโฮสต์เองหรือทำงานผ่าน OWin stack โดยไม่มีท่อ System.Web ไม่เกี่ยวข้องกับการแก้ปัญหานี้แม้ว่า
Rick Strahl

15

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

public class TextPlainFormatter : MediaTypeFormatter
{
    public TextPlainFormatter()
    {
        this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
    }

    public override bool CanWriteType(Type type)
    {
        return type == typeof(string);
    }

    public override bool CanReadType(Type type)
    {
        return type == typeof(string);
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext transportContext)
    {
        return Task.Factory.StartNew(() => {
            StreamWriter writer = new StreamWriter(stream);
            writer.Write(value);
            writer.Flush();
        });
    }

    public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
    {
        return Task.Factory.StartNew(() => {
            StreamReader reader = new StreamReader(stream);
            return (object)reader.ReadToEnd();
        });
    }
}

อย่าลืมเพิ่มลงในการกำหนดค่า Global web api ของคุณ

config.Formatters.Add(new TextPlainFormatter());

ตอนนี้คุณสามารถส่งสตริงวัตถุไปยัง

this.Request.CreateResponse(HttpStatusCode.OK, "some text", "text/plain");


12
  • โปรดระวังอย่าใช้บริบทใน ASP.NET Web API มิฉะนั้นคุณจะเสียใจไม่ช้าก็เร็ว ลักษณะอะซิงโครนัสของ ASP.NET Web API ทำให้ใช้HttpContext.Currentความรับผิด
  • ใช้ตัวจัดรูปแบบข้อความธรรมดาและเพิ่มลงในฟอร์แมตของคุณ มีหลายสิบรอบ คุณสามารถเขียนของคุณได้อย่างง่ายดาย WebApiContribมีหนึ่ง
  • คุณสามารถบังคับได้โดยตั้งค่าส่วนหัวประเภทเนื้อหาhttpResponseMessage.Headersเป็นtext/plainในคอนโทรลเลอร์ของคุณหากคุณได้ลงทะเบียนฟอร์แมตเตอร์ข้อความธรรมดาแล้ว

ไม่ต้องกังวลฉันไม่ได้บอกเป็นนัยหรือตั้งใจที่จะใช้วัตถุ HttpContext ฉันเพิ่งเพิ่มเพื่อแสดงให้เห็นว่าจะทำอย่างไรใน ASP.NET แบบคลาสสิก
Magnus Johansson

เอาล่ะ waddayknow ฉันมี WebAPIContrib ที่อ้างอิงอยู่แล้วบางครั้งก็ง่าย
Magnus Johansson

@ แม็กนัสชัวร์. อันที่จริงฉันเปลี่ยนถ้อยคำหลังจากอ่านสิ่งที่ฉันเขียน แต่การอ่านคำตอบอื่นทำให้ฉันเครียดในจุดแรก
Aliostad

คุณกำลังบอกว่าจะไม่ใช้ HttpContext.Current ทางเลือกอื่นคืออะไร?
surya

@spiderdevil ใช่มันเป็นอย่างที่ฉันพูด คุณไม่จำเป็นต้องใช้มันส่งคำขอ / ตอบกลับ / กำหนดค่าโดยตรง
Aliostad

6

เมื่อยอมรับ: ข้อความ / ธรรมดาใช้ไม่ได้แสดงว่าไม่มีฟอร์แมตเตอร์ที่ลงทะเบียนสำหรับประเภทใบ้ข้อความ

คุณสามารถมั่นใจได้ว่าไม่มีการจัดรูปแบบสำหรับประเภท mime ที่ระบุโดยรับรายการของรูปแบบที่รองรับทั้งหมดจากการกำหนดค่าบริการ

สร้างฟอร์แมตเตอร์ชนิดสื่อที่ตรงไปตรงมามากซึ่งรองรับชนิดข้อความใบ้

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters


หวังว่าฉันจะยอมรับคำตอบของคุณได้เช่นกันคำตอบที่ได้รับการยอมรับจะช่วยฉันไม่ให้มีปัญหาในการเขียนฟอร์แมตเตอร์ของตัวเอง +1 เป็นอย่างน้อย
Magnus Johansson

0

ส่วนขยายดังต่อไปนี้สามารถลดจำนวนบรรทัดและทำให้โค้ดของคุณสวยงาม:

public static class CommonExtensions
{
    public static HttpResponseMessage ToHttpResponseMessage(this string str)
    {
        var resp = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(str, System.Text.Encoding.UTF8, "text/plain")
        };

        return resp;
    }
}


ตอนนี้คุณสามารถใช้ส่วนขยายที่กำหนดไว้ในWeb API:

public class HomeController : ApiController
{
    [System.Web.Http.HttpGet]
    public HttpResponseMessage Index()
    {
        return "Salam".ToHttpResponseMessage();
    }
}


โดยการกำหนดเส้นทาง{DOMAIN}/api/Home/Indexคุณจะเห็นข้อความธรรมดาต่อไปนี้:

MyPlainTextResponse


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