Подтвердить что ты не робот

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 в моем контроллере?

4b9b3361

Ответ 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.