Больше странностей Ajax / MVC - PullRequest
4 голосов
/ 16 августа 2010

Последние несколько ночей я ломал голову над странным поведением с моим проектом MVC2.

У меня есть результат действия MVC, который принимает ID проекта и сложный объект Json, выглядя так:

[HttpPost]
public JsonResult AddStory(int projectid, Story story)
{
    try
    {
        Project prj = repository.Single(p => p.ID == projectid);

        //prj.Stories.Add(story);
        //repository.SaveChanges();

        return Json(new { Result = story });
    }
    catch (Exception ex)
    {
        ErrorSignal.FromCurrentContext().Raise(ex);

        return Json(new { Result = 0 });
    }
}

Мой код jQuery для отправки сложного объекта до сих пор выглядит следующим образом (сложный объект имеет больше свойств, чем этот, но я пытаюсь использовать только эти два для отладки):

$.ajax({
    url: '/Project/1/AddStory',
    data: { Summary: myStory.Summary, Size: myStory.Size },
    dataType: 'json',
    processData: false,
    traditional: true,
    type: 'POST'
});

Моя проблема в том, что независимо от того, как я размещаю этот объект; даже если я отправляю его на другой контроллер и выполняю действие, кажется, что запрос никогда не попадает на сервер, и страница автоматически перенаправляется на следующий URL:

http://localhost:57932/Project/1/Board?story.Summary=Test+description&story.Size=8&story.Priority=2&story.Deadline=08%2F31%2F2010&story-owner=http%3A%2F%2Ftestaccount.myopenid.com

Консоль Firebug показывает ошибку в jQuery.min.js с правильными заголовками, но без значений POST или RESPONSE.

Я попытался посмотреть на трафик в Fiddler и вижу, что заголовки запроса выглядят правильно:

Принять заявку / JSON, текст / javascript, /

И определенно объект отправляется в строке запроса. Так чего мне не хватает? Я уверен, что должна быть простая причина, по которой все так портится.

Edit:

Маршруты (из Global.asax) являются следующими плюс сопоставленный маршрут по умолчанию:

    routes.MapRoute(
        "Project",
        "Project/{projectid}/{action}/{id}",
        new { controller = "Project", action = "Index", id = "" });

Ответы [ 4 ]

3 голосов
/ 20 августа 2010

Оказывается, решение простое.Вызов ajax в этой текущей форме просто не отправляет данные POST из-за настройки processData = false.Измените jQuery на это:

$.ajax({
    url: '/Project/1/AddStory',
    data: { Summary: myStory.Summary, Size: myStory.Size },
    dataType: 'json',
    traditional: true,
    type: 'POST'
});

Документ API jQuery немного тупой:

processData
По умолчанию: true

По умолчанию данные, передаваемые в параметр данных как объект (технически, что угодно, кроме строки), будут обрабатываться и преобразовываться в строку запроса, соответствующую типу содержимого по умолчанию "application / x-www-form-urlencoded».Если вы хотите отправить DOMDocument или другие необработанные данные, установите для этого параметра значение false.

Моя интерпретация заключается в том, что значение false, $.ajax не преобразует объект данных как значение именипараметры.Не уверен, для чего он используется, но установка его в false кажется плохой идеей:)

1 голос
/ 24 августа 2010

У меня нет вашего полного исходного кода, поэтому трудно сказать почему у вас есть запрос на перенаправление с '/ Project / 1 / AddStory' на

http://localhost:57932/Project/1/Board?story.Summary=Test+description&...

T попытался воспроизвести вашу проблему. Я создал небольшое приложение MVC 2 с действием AddStory в контроллере Project, которое выглядит как ваше:

[HttpPost]
public JsonResult AddStory (int projectid, Story story) {
    return Json (new {
        Result = story,
        myNewProjectid = projectid,
        myNewSummary = story.Summary + ". " + "Bla bla",
        myNewSize = story.Size + 20
    });
}

где Story класс, который я объявил так же, как следующий:

public class Story {
    public string Summary { get; set; }
    public int Size { get; set; }
}

Я вставил маршрут, как вы опубликовали, и добавил следующий jQuery sctipt в Index виде Home контроллера:

jQuery(document).ready(function () {
    var myStory = { Summary: 'Test description', Size: 8 };
    $.ajax({
        url: '/Project/1/AddStory',
        data: { Summary: myStory.Summary, Size: myStory.Size },
        dataType: 'json',
        success: function (data, textStatus, xhr) {
            alert('myNewSummary="' + data.myNewSummary +
                  '", Result.Summary="' + data.Result.Summary +
                  '", Result.Size=' + data.Result.Size);
        },
        error: function (xhr, textStatus, errorThrown) {
            alert("error");
        },
        type: 'POST'
    });
});

Код работает без проблем и выдает сообщение с текстом myNewSummary="Test description. Bla bla", Result.Summary="Test description", Result.Size=8 как ожидается.

Вы можете продолжать использовать traditional: true, если у вас возникают проблемы с размещением более сложных структур данных. Текущий тест не требует использования traditional: true.

Чтобы вам было проще сравнивать ваш код с моим рабочим примером, я поместил полный проект Visual Studio 2010 в http://www.ok -soft-gmbh.com / ForStackOverflow / MvcApplicationJson.zip . Надеюсь, это поможет вам быстро найти ошибку в своем коде и исправить ее.

0 голосов
/ 26 августа 2010

Тьфу. Выпуск PEBKAC.

Оказывается, проблема заключалась в том, что у меня раньше были поля ввода внутри набора <form> тегов, а jQuery послушно отправлял мой контент - которому явно не нужно явно указывать идентификатор проекта, поскольку он является частью строки запроса. и обрабатывается MVC - а затем, увидев форму, выполнил вызов «submit», который перенаправил обратно на ту же страницу.

Извините за трату времени каждого. Был несколько действительно полезных советов и много практических идей для решения моей проблемы.

0 голосов
/ 23 августа 2010

Я бы посоветовал вам использовать $.post вместо

            var jsonbox = { Summary: myStory.Summary, Size: myStory.Size }
            $.post("/Project/1/AddStory", jsonbox, function doneit(data) {
                if (data.succes == true) {
                    //do something like return a message 'saved, all ok'
                } else {
                    /give an error.
                }
            }, "json");

я всегда использую этот стиль действия

    [HttpPost]
    public ActionResult SomeAction(int id, FormCollection collection) {
        try {
           //some code
        } catch (Exception e) {
            return Json(new { succes = false, error = "An error occured. Details: " + e.Message });
        }

        return Json(new { succes = true });
    }

$.post работает хорошо, если вам не нужно ничего необычного - просто сообщение, переменная для отправки и функция, выполняемая при получении результата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...