Web API 依據 Accept 標頭進行內容協商:瀏覽器通常送 text/html, application/xhtml+xml, application/xml;q=0.9,導致預設回傳 XML。若需強制 JSON,有三種主流做法。
// Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// 移除 XML 格式化器,只保留 JSON
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
}
優點:一行程式碼、全域生效。
缺點:string 回傳型別會被序列化為 "value"(含雙引號),非純 JSON 字串;無法針對個別 Action 控制。
public HttpResponseMessage GetUser(int id)
{
var user = _service.GetUser(id);
var json = JsonConvert.SerializeObject(user); // Newtonsoft.Json
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
}
// 字串回傳不被加引號
public HttpResponseMessage GetRawString()
{
string raw = "hello";
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(raw, Encoding.UTF8, "application/json") // 純字串內容
};
}
為避免重複撰寫,可封裝擴充方法:
public static class HttpResponseMessageExtensions
{
public static HttpResponseMessage AsJson(this object obj, HttpStatusCode status = HttpStatusCode.OK)
{
string content;
if (obj is string || obj is char)
content = obj.ToString(); // 字串直接輸出,不序列化
else
content = JsonConvert.SerializeObject(obj);
return new HttpResponseMessage(status)
{
Content = new StringContent(content, Encoding.UTF8, "application/json")
};
}
}
// 使用
public HttpResponseMessage GetUser(int id) => _service.GetUser(id).AsJson();
public HttpResponseMessage GetMessage() => "操作成功".AsJson();
public class JsonOnlyNegotiator : IContentNegotiator
{
private readonly JsonMediaTypeFormatter _formatter = new JsonMediaTypeFormatter();
public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable formatters)
{
return new ContentNegotiationResult(_formatter, new MediaTypeHeaderValue("application/json"));
}
}
// WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });
// 全域套用
config.Services.Replace(typeof(IContentNegotiator), new JsonOnlyNegotiator());
// 或針對特定控制器
// config.MapHttpAttributeRoutes();
// [JsonOnly] 自訂 Attribute 套用在 Controller/Action
}
優點:可精細控制套用範圍、保留內容協商架構。
缺點:程式碼較多、同樣面臨 string 加引號問題。
| 方法 | 適用範圍 | string 回傳 | 複雜度 | 備註 |
|---|---|---|---|---|
| 移除 XML Formatter | 全域 | 變成 "str" | 極低 | 最快,但副作用大 |
| HttpResponseMessage 手動序列化 | 單一 Action / 擴充方法 | 純字串 | 中 | 最靈活,推薦封裝為 BaseController 或擴充方法 |
| IContentNegotiator | 全域 / 控制器 / Action | 變成 "str" | 高 | 架構純正,但需自行處理 string 特例 |
ASP.NET Core MVC / Web API 預設即回傳 JSON,且 string 回傳為純文字(text/plain),若需 JSON 字串請回傳 JsonResult 或物件。無需任何設定即可獲得正確行為。
string 加引號問題。HttpResponseMessage + 擴充方法),掌控序列化細節。