我正在尝试在中编写Web API控制器。NET Core接收Worldpay通知。
我已经用XmlSerializerInputFormatter做了一个AddMvc;调整的";有效载荷的版本。
services.AddMvc(config =>
{
config.InputFormatters.Add(new XmlSerializerInputFormatter(config));
});
我的测试控制器
[HttpPost]
[Route("SendDocument")]
[Consumes("application/xml")]
public ActionResult SendDocument([FromBody] paymentService payment)
{
return Ok();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE paymentService PUBLIC "-//Worldpay//DTD Worldpay PaymentService v1//EN"
"http://dtd.worldpay.com/paymentService_v1.dtd">
<paymentService version="1.4" merchantCode="Your_merchant_code">
<notify>
<orderStatusEvent orderCode="ExampleOrder1">
<payment>
<paymentMethod>ECMC-SSL</paymentMethod>
<amount value="2400" currencyCode="EUR" exponent="2" debitCreditIndicator="credit"/>
<lastEvent>AUTHORISED</lastEvent>
<AuthorisationId id="622206"/>
<balance accountType="IN_PROCESS_AUTHORISED">
<amount value="2400" currencyCode="EUR" exponent="2" debitCreditIndicator="credit"/>
</balance>
<cardNumber>5255********2490</cardNumber>
<riskScore value="0"/>
</payment>
</orderStatusEvent>
</notify>
</paymentService>
然而,它们在开始时包含一个DOCTYPE标记,如果我将其添加回有效负载,它就会失败。没有DOCTYPE,它可以完美地工作
我已经做了很多搜索,看到了关于忽略DTD等的信息,但我不知道如何使用InputFormatter来做到这一点。
如何让InputFormatter忽略文件中的这个DTD DOCTYPE标记?
经过一番折腾,我得到了一些对其他有用的东西
所以我的ConfigureServices包含
services.AddMvc(config =>
{
config.InputFormatters.Insert(0, new RawXmlRequestBodyFormatter());
});
我创建了一个Raw Formatter,它以字符串的形式通过XML,删除了以<!DOCTYPE
public class RawXmlRequestBodyFormatter : InputFormatter
{
public RawXmlRequestBodyFormatter()
{
SupportedMediaTypes.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/xml"));
SupportedMediaTypes.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("text/xml"));
}
/// <summary>
/// Allow text/xml, application/xml only
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Boolean CanRead(InputFormatterContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var contentType = context.HttpContext.Request.ContentType;
return (contentType == "text/xml" || contentType == "application/xml");
}
/// <summary>
/// Handle xml results
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var contentType = context.HttpContext.Request.ContentType;
var httpContext = context.HttpContext;
if (contentType == "application/xml" || contentType == "text/xml")
{
using var reader = new StreamReader(httpContext.Request.Body, Encoding.UTF8);
StringBuilder xml = new StringBuilder();
try
{
while(true)
{
var Line = await ReadLineAsync(reader, context);
if (Line != null)
xml.AppendLine(Line);
else
break;
}
}
catch
{
return await InputFormatterResult.FailureAsync();
}
return await InputFormatterResult.SuccessAsync(xml.ToString());
}
return await InputFormatterResult.FailureAsync();
}
/// <summary>
/// Read next line, Skip any lines starting with DOCTYPE
/// </summary>
/// <param name="reader"></param>
/// <param name="context"></param>
/// <returns></returns>
private async Task<string> ReadLineAsync(StreamReader reader, InputFormatterContext context)
{
string line = null;
do
{
line = await reader.ReadLineAsync();
} while (line != null && line.StartsWith("<!DOCTYPE"));
return line;
}
}
在我的控制器中,我这样使用它。我获取RAW XML字符串,将其反序列化为我编写的paymentService类,然后以JSON形式返回,这样您就可以看到它在POSTMAN 中的工作
[HttpPost]
[Route("SendDocument")]
[Consumes("application/xml")]
public ActionResult SendDocument([FromBody] string raw)
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(paymentService), new XmlRootAttribute("paymentService"));
StringReader stringReader = new StringReader(raw);
var o = (paymentService)serializer.Deserialize(stringReader);
return Ok(o);
}
catch (Exception ex)
{
}
return Ok();
}
我的支付服务类别是这些,提供完整性
public class amount
{
public amount()
{
}
[XmlAttribute]
public string value { get; set; }
[XmlAttribute]
public string currencyCode { get; set; }
[XmlAttribute]
public string exponent { get; set; }
[XmlAttribute]
public string debitCreditIndicator { get; set; }
}
public class balance
{
public balance()
{
}
[XmlAttribute]
public string accountType { get; set; }
[XmlElement]
public amount amount { get; set; }
}
public class riskScore
{
public riskScore()
{
}
[XmlAttribute]
public string value { get; set; }
}
public class authorisationId
{
public authorisationId()
{
}
[XmlAttribute]
public string id { get; set; }
}
public class payment
{
public payment()
{
}
[XmlElement]
public string paymentMethod { get; set; }
[XmlElement]
public amount amount { get; set; }
[XmlElement]
public string lastEvent { get; set; }
[XmlElement]
public authorisationId AuthorisationId { get; set; }
[XmlElement]
public balance balance { get; set; }
[XmlElement]
public string cardNumber { get; set; }
[XmlElement]
public riskScore riskScore { get; set; }
}
public class orderStatusEvent
{
public orderStatusEvent()
{
}
[XmlAttribute]
public string orderCode { get; set; }
[XmlElement]
public payment payment { get; set; }
}
public class notify
{
public notify()
{
}
[XmlElement]
public orderStatusEvent orderStatusEvent { get; set; }
}
[Serializable]
public class paymentService
{
public paymentService()
{
}
[XmlAttribute]
public string version { get; set; }
[XmlAttribute]
public string merchantCode { get; set; }
[XmlElement]
public notify notify { get; set; }
}
我希望这能节省一些时间。WorldPay在提供信息方面毫无用处,要达到这一点需要数周的时间。