【问题标题】:ASP.NET 5 MVC 6 XML response headerASP.NET 5 MVC 6 XML 响应标头
【发布时间】:2016-03-17 08:04:53
【问题描述】:

我有一个控制器,它返回一个定制的 XML 字符串,因为使用 Api 的应用程序需要一个特定格式,没有任何属性,并且默认 XML 字符串顶部没有 <?xml ... /> 标记。 编辑:消费者也没有请求“text/xml”的请求标头。

我的 Startup.cs 中的 ConfigureServices 如下所示:

    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        var mvc = services.AddMvc();

        mvc.AddMvcOptions(options =>
        {
            options.InputFormatters.Remove(new JsonInputFormatter());
            options.OutputFormatters.Remove(new JsonOutputFormatter());
        });

        mvc.AddXmlDataContractSerializerFormatters();
    }

在我的控制器中,我尝试了一些我在 Internet 上找到的解决方案(已注释掉),但没有一个在 chrome devtools 中给我带有响应标头“Content-Type: application/xml”的 XML 内容:

[HttpGet("{ssin}")]
[Produces("application/xml")]
public string Get(string ssin)
{    
    var xmlString = "";
    using (var stream = new StringWriter())
    {
        var xml = new XmlSerializer(person.GetType());
        xml.Serialize(stream, person);
        xmlString = stream.ToString();
    }
    var doc = XDocument.Parse(xmlString);
    doc.Root.RemoveAttributes();
    doc.Descendants("PatientId").FirstOrDefault().Remove();
    doc.Descendants("GeslachtId").FirstOrDefault().Remove();
    doc.Descendants("GeboorteDatumUur").FirstOrDefault().Remove();
    doc.Descendants("OverledenDatumUur").FirstOrDefault().Remove();
    Response.ContentType = "application/xml";
    Response.Headers["Content-Type"] = "application/xml";

    /*var response = new HttpResponseMessage
    {
        Content = new  StringContent(doc.ToString(), Encoding.UTF8, "application/xml"),
    };*/
    return doc.ToString(); //new HttpResponseMessage { Content = new StringContent(doc., Encoding.UTF8, "application/xml") };
}

我可以尝试什么让它响应 application/xml?

EDIT1(根据 Luca Ghersi 的回答): 启动.cs:

    public Startup(IHostingEnvironment env)
    {
        // Set up configuration sources.
        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        var mvc = services.AddMvc(config => {
            config.RespectBrowserAcceptHeader = true;
            config.InputFormatters.Add(new XmlSerializerInputFormatter());
            config.OutputFormatters.Add(new XmlSerializerOutputFormatter());
        });

        mvc.AddMvcOptions(options =>
        {
            options.InputFormatters.Remove(new JsonInputFormatter());
            options.OutputFormatters.Remove(new JsonOutputFormatter());
        });

        //mvc.AddXmlDataContractSerializerFormatters();
    }
    /*
     * Preconfigure if the application is in a subfolder/subapplication on IIS
     * Temporary fix for issue: https://github.com/aspnet/IISIntegration/issues/14 
     */
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.Map("/rrapi", map => ConfigureApp(map, env, loggerFactory));
    }


    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void ConfigureApp(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        //app.UseIISPlatformHandler();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

    // Entry point for the application.
    public static void Main(string[] args) => WebApplication.Run<Startup>(args);

控制器:

        [HttpGet("{ssin}")]
    [Produces("application/xml")]
    public IActionResult Get(string ssin)
    {
        var patient = db.Patienten.FirstOrDefault(
            p => p.Rijksregisternummer.Replace(".", "").Replace("-", "").Replace(" ", "") == ssin
        );

        var postcode = db.Postnummers.FirstOrDefault(p => p.PostnummerId == db.Gemeentes.FirstOrDefault(g =>
            g.GemeenteId == db.Adressen.FirstOrDefault(a =>
                a.ContactId == patient.PatientId && a.ContactType == "pat").GemeenteId
            ).GemeenteId
        ).Postcode;

        var person = new person
        {
            dateOfBirth = patient.GeboorteDatumUur.Value.ToString(""),
            district = postcode,
            gender = (patient.GeslachtId == 101 ? "MALE" : "FEMALE"),
            deceased = (patient.OverledenDatumUur == null ? "FALSE" : "TRUE"),
            firstName = patient.Voornaam,
            inss = patient.Rijksregisternummer.Replace(".", "").Replace("-", "").Replace(" ", ""),
            lastName = patient.Naam
        };
        var xmlString = "";
        using (var stream = new StringWriter())
        {
            var opts = new XmlWriterSettings { OmitXmlDeclaration = true };
            using (var xw = XmlWriter.Create(stream, opts))
            {
                var xml = new XmlSerializer(person.GetType());
                xml.Serialize(xw, person);
            }
            xmlString = stream.ToString();
        }
        var doc = XDocument.Parse(xmlString);
        doc.Root.RemoveAttributes();
        doc.Descendants("PatientId").FirstOrDefault().Remove();
        doc.Descendants("GeslachtId").FirstOrDefault().Remove();
        doc.Descendants("GeboorteDatumUur").FirstOrDefault().Remove();
        doc.Descendants("OverledenDatumUur").FirstOrDefault().Remove();

        return Ok(doc.ToString()); 

【问题讨论】:

    标签: c# asp.net xml asp.net-mvc asp.net-4.6


    【解决方案1】:

    创建一个XmlWriter 填充选项以阻止创建 XML 声明。然后使用采用XmlWriterXmlSerializer.Serialize 重载之一。 XmlWriter 可以写入字符串(参见here):

    using (var sw = new StringWriter()) {
      var opts = new XmlWriterSettings { OmitXmlDeclaration = true };
      using (var xw = XmlWriter.Create(sw, opts) {
    
        xml.Serialize(xw, person);
    
      }
      xmlString = sw.ToString();
    }
    

    NB您已经在设置Response.ContentType,因此如果覆盖它,请设置其他内容。检查可能覆盖您的设置的过滤器和模块。

    【讨论】:

    • 这是一个文件新项目,只有 1 个控制器和 2 个动作(显示 api 正在工作和 ssin 动作的索引)和“人”类文件,所以我怀疑某些东西会覆盖它。尽管如此,我已经将我的代码更新为您添加的内容,但它仍然返回 text/plain。
    • @Asum This answer 可能会有所帮助:看来您无法直接直接操作内容类型。
    • 我解决了标题,但现在我正在使用 XMLformatter,现在 XML 再次具有属性。有没有办法改变格式化程序将对象序列化为 XML 的方式?
    • @Asum 有很多选择(这通常是我发现自己编写 XML 更容易的原因:更容易控制)。
    【解决方案2】:

    看起来article 就是您要查找的内容。 与其尝试手动操作,不如尝试使用 XML 格式化程序,如下所示:

     // Add framework services.
      services.AddMvc(config =>
      {
        // Add XML Content Negotiation
        config.RespectBrowserAcceptHeader = true;
        config.InputFormatters.Add(new XmlSerializerInputFormatter());
        config.OutputFormatters.Add(new XmlSerializerOutputFormatter());
      });
    

    这个 outputFormatter 依赖于:

    "Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-rc1-final"
    

    您还需要将[Produces("application/xml")] 保留为方法属性,详见此answer

    还可以查看这篇关于 MVC 6 中 Formatters 的非常详细的文章。它是更新版本。我想这会有所帮助。

    要修改响应的生成方式,您可以使用 XmlWriterSettings 选项对象,如下所示(更多信息here):

    var settings = new XmlWriterSettings { OmitXmlDeclaration = true };
    config.OutputFormatters.Add(new XmlSerializerOutputFormatter(settings);
    

    希望对你有帮助!

    【讨论】:

    • 感谢您的快速响应,但遗憾的是(我忘了提及,将其添加到我的帖子中)消费者没有添加“text/xml”的请求标头,因此无法选择内容协商.我必须强制它请求 xml 或强制响应上的标头说它返回 'application/xml'
    • 忘记内容协商吧。如果您像以前那样删除 JSON 格式化程序,只保留 XML,我猜它应该可以工作,因为它将是 ASP.NET 唯一可用的格式化程序。
    • 仍然返回'text/plain'。我将在我的帖子中添加一个 EDIT1 以显示我的更改。
    • 您是否在方法上留下了 [Produces("application/xml")]?我更新了我的答案。
    • 是的,正如我在 EDIT1 中看到的那样,我添加了完整的控制器 getSSIN 操作代码和完整的 Startup.cs 代码,以防您发现其中的另一个错误。
    猜你喜欢
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多