ASP.NET MVC4 WebAPI и отправка XML-данных
Мне не хватает трюка с новым webapi - я пытаюсь отправить строку xml через почтовый запрос и не испытываю большой удачи.
Передняя часть использует jQuery следующим образом:
$(document = function () {
$("#buttonTestAPI").click(function () {
var d = " <customer><customer_id>1234</customer_id></customer>";
$.ajax({
type: 'POST',
contentType: "text/xml",
url: "@Url.Content("~/api/Customer/")",
data: d,
success: function (result) {
var str = result;
$("#output").html(str);
}
});
});
});
Мой контроллер на данный момент довольно простой - просто по умолчанию для действия post - попытка вернуть то, что было передано:
public string Post(string value)
{
return value;
}
Однако значение "значение" несколько раз null. Странно, когда я меняю свои данные в jquery на что-то вроде этого:
d = "<customer_id>1234</customer_id>";
Затем я получаю "значение" в моем контроллере как 1234.
Как я могу получить доступ к более сложной строке xml в моем контроллере?
Ответы
Ответ 1
Ниже вы можете прочитать необработанное XML-сообщение через POST с помощью метода Web API:
public void PostRawXMLMessage(HttpRequestMessage request)
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(request.Content.ReadAsStreamAsync().Result);
}
Вы можете отлаживать и проверять тело, заголовки и т.д., и увидите, что XML-материал отправлен. Я использовал Fiddler Composer для создания HTTP POST, и это работает хорошо.
Ответ 2
Вы отправляете тип контента text/xml
, но вы определили свой параметр как string
. В идеале ваш XML должен быть сопоставлен с классом, чтобы его можно было десериализовать.
Итак, если вам нужен raw xml, он пока не поддерживается. Веб-API в настоящее время предназначен для сериализации MediaTypeFormatters и пропущенных форм-форм, но они легко могут быть построены.
Этот вариант является минимальным таким форматом, поддерживающим только чтение в вашем случае и основанным на бета-установщике (а не ночном исходном коде, поскольку он существенно изменился):
public class TextMediaTypeFormatter : MediaTypeFormatter
{
public TextMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
}
protected override bool CanReadType(Type type)
{
return type == typeof (string);
}
protected override System.Threading.Tasks.Task<object> OnReadFromStreamAsync(Type type, Stream stream,
HttpContentHeaders contentHeaders,
FormatterContext formatterContext)
{
var taskCompletionSource = new TaskCompletionSource<object>();
try
{
var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
taskCompletionSource.SetResult(s);
}
catch (Exception e)
{
taskCompletionSource.SetException(e);
}
return taskCompletionSource.Task;
}
}
И чтобы использовать его, просто добавьте его в коллекцию formatters:
GlobalConfiguration.Configuration.Formatters.Insert(0, new TextMediaTypeFormatter());
Ответ 3
Любой, кто ищет обновленную версию ответа Aliostad выше от бета-версии к RC asp.net mvc 4 web api (незначительные изменения привели к небольшой переделке для меня).
public class TextMediaTypeFormatter : MediaTypeFormatter
{
public TextMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
}
public override bool CanReadType(Type type)
{
if (type == typeof(String))
return true;
else
return false;
}
public override bool CanWriteType(Type type)
{
if (type == typeof(String))
return true;
else
return false;
}
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
{
var taskCompletionSource = new TaskCompletionSource<object>();
try
{
var memoryStream = new MemoryStream();
readStream.CopyTo(memoryStream);
var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
taskCompletionSource.SetResult(s);
}
catch (Exception e)
{
taskCompletionSource.SetException(e);
}
return taskCompletionSource.Task;
}
}
Ответ 4
Что мне удалось решить, добавив это:
static SubscriberController()
{
//Needed for xml deserialization to work
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
}
(SubscriberController
- мой класс, который расширяет ApiController
, а выше - статический конструктор, поэтому он будет запускаться один раз).
Не уверен, что это также необходимо, но я добавил атрибут [FromBody]
к моему параметру, например:
public async Task<HttpResponseMessage> SynchronizeImax( [FromBody] SynchronizeRequest synchronizeRequest )
{
//...
}
Самое приятное в этом - это то, что вы можете легко обрабатывать как входные данные XML, так и JSON.