让[FormatFilter]
在我的MVC Core 2.1.3 API中工作非常困难。
我希望端点支持JSON和XML,所以我编写了以下代码:
Startup
类,该类继承自StartupCore
类:
public class Startup : StartupCore
{
protected override void OnConfigure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
IApplicationLifetime appLifetime) => AutoMappings.Initialize();
}
(部分)这个StartupCore
类
//....
services
.AddCors()
.AddMvcCore()
.AddApiExplorer()
.AddJsonFormatters()
.AddXmlSerializerFormatters() //With or without this line; no luck
.AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
})
.AddMvcOptions(options =>
{
options.InputFormatters.Add(new PlainTextInputFormatter());
options.OutputFormatters.Add(new CsvOutputFormatter());
options.FormatterMappings.SetMediaTypeMappingForFormat("csv", MediaTypeHeaderValue.Parse("text/csv"));
options.OutputFormatters.Add(new XmlSerializerOutputFormatter());
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", MediaTypeHeaderValue.Parse("application/xml"));
})
//.......
当我在控制器上使用FormatFilter
属性时,例如
[HttpGet]
[FormatFilter]
[Route("/public/feed/{format}")]
public async Task<IActionResult> CreateFeed(string format)
{
//
}
我收到错误消息: Autofac.Core.Registration.ComponentNotRegisteredException:所请求的服务“ Microsoft.AspNetCore.Mvc.Formatters.FormatFilter”尚未注册。
但是,当我使用Produces
属性时,它会为我提供XML数据。
[HttpGet]
[Produces("application/xml")]
[Route("/public/feed/{format}")]
public async Task<IActionResult> CreateFeed(string format)
{
//
}
我最终可能有两个端点;一个用于JSON,一个用于XML,但我宁愿使用FormatFilter
作为一个终结点。
那么我在这里想念什么?
解决方法:目前,我正在使用Produces
属性[Produces("application/json", "application/xml"]
使用的来源:https://andrewlock.net/formatting-response-data-as-xml-or-json-based-on-the-url-in-asp-net-core/
答案 0 :(得分:2)
如果端点或控制器使用FormatFilter属性,则应通过AddFormatterMappings注册相应的服务:
package pl.test.rest;
import pl.test.model.Mestechnologygroup;
import pl.test.repo.TechnologyGroupRepo;
import javax.inject.Inject;
import javax.validation.constraints.Min;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import java.util.List;
import static javax.transaction.Transactional.TxType.REQUIRED;
import static javax.transaction.Transactional.TxType.SUPPORTS;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@Path("/tg")
public class TechnologyGroupEndpoint{
@Inject
private TechnologyGroupRepo technologyGroupRepo;
@GET
@Path("/{id : \\d+}")
@Produces(APPLICATION_JSON)
public Response getBook(@PathParam("id") @Min(1) Integer id) {
Mestechnologygroup mestechnologygroup = technologyGroupRepo.find(id);
if (mestechnologygroup == null)
return Response.status(Response.Status.NOT_FOUND).build();
return Response.ok(mestechnologygroup).build();
}
@DELETE
@Path("/d/{id : \\d+}")
public Response deleteBook(@PathParam("id") @Min(1) Integer id) {
technologyGroupRepo.delete(id);
return Response.noContent().build();
}
@GET
@Produces(APPLICATION_JSON)
public Response getBooks() {
List<Mestechnologygroup> mestechnologygroups = technologyGroupRepo.findAll();
if (mestechnologygroups.size() == 0)
return Response.status(Response.Status.NO_CONTENT).build();
return Response.ok(mestechnologygroups).build();
}
}
答案 1 :(得分:1)
在StartupCore
中,您依靠OnMvcCoreServiceConfiguration
事件添加XML输出格式化程序。这将在您呼叫AddMvcCore
的线路上触发。然后,稍后,您再次调用AddMvcOptions
,它将覆盖您之前的调用。在第二个调用中,您无需添加XML格式化程序,因此它实际上从未添加。
您需要注意发生的事情的异步性质。您正在传递一个将在应用程序启动时调用的操作,因此,第一次调用AddMvcOptions
时,实际上还没有任何反应。当您以后再次调用它时,您将设置一个最终将要使用的新操作,以替换先前设置的操作。
答案 2 :(得分:0)
我的.Net Core 2.1 WebAPI项目也遇到了这个问题,发现我需要在Ajax调用中显式设置“接受”请求标头。在我最初的.Net 4.7 Web API项目中,将dataType属性设置为'json'或'xml'就足以返回正确的内容类型,但对于.Net Core而言似乎并不足够。我的Ajax通话如下:
$.ajax({
type: 'GET',
beforeSend: function (request)
{
request.setRequestHeader("Accept", "application/xml");
// or for json request.setRequestHeader("Accept", "application/json");
},
traditional: true,
url: uri,
contentType: 'application/json; charset=utf-8',
dataType: 'xml',
// or for json dataType: 'json',
success: function (data)
{
...
},
error: function (req, status, err)
{
...
}
});
我还需要防止缓存,以确保每次通过在ResponseCache装饰器中设置NoStore属性来确保将正确的Accept标头传递给我的控制器方法:
[ResponseCache(NoStore = true)]
public ActionResult Get(string customerName)
{
...
}