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

Отображение knockoutjs из/в объект POCO

Есть ли способ сопоставления от/к POCO и наблюдаемым нокаутам?

У меня есть класс Note:

public class Note
{
    public int ID { get; set; }
    public string Date { get; set; }
    public string Content { get; set; }
    public string Category { get; set; }
    public string Background { get; set; }
    public string Color { get; set; }
}

и это мой javascript:

$(function () {
    ko.applyBindings(new viewModel());
});

function note(date, content, category, color, background) {
    this.date = date;
    this.content = content;
    this.category = category;
    this.color = color;
    this.background = background;
}

function viewModel () {
    this.notes = ko.observableArray([]);
    this.newNoteContent = ko.observable();

    this.save = function (note) {
        $.ajax({
                url: '@Url.Action("AddNote")',
                data: ko.toJSON({ nota: note }),
                type: "post",
                contentType: "json",
                success: function(result) { }

            });
    }

    var self = this;
    $.ajax({
        url: '@Url.Action("GetNotes")',
        type: "get",
        contentType: "json",
        async: false,
        success: function (data) {
            var mappedNotes = $.map(data, function (item) {
                return new note(item.Date, item.Content, item.Category, item.Color, item.Background);
            });
            self.notes(mappedNotes);
        }
    });
}

Игнорируйте тот факт, что функция сохранения не используется (чтобы упростить код здесь).

Итак, когда я загружаю страницу, я вызываю сервер, и я получаю список объектов Note, и я сопоставляю его в javascript. Обратите внимание, что идентификатор не отображается, потому что мне это не нужно в моем представлении.

Пока все хорошо, я вижу заметки на экране, но как я могу сохранить заметки на сервере?

Я попытался преобразовать заметку (Im, сохраняющую только новую заметку, а не всю коллекцию) в JSON, и отправить ее на мой контроллер, но я не знаю, как получить доступ к заметке в контроллере. Я пробовал:

    public string AddNote(string date, string content, string category, string background, string color)
    {
        // TODO
    }

но не работает. Я хочу иметь что-то вроде:

public string AddNote(Note note) {}

(Btw, какой лучший результат для метода, который просто сохраняет данные в DB? void?)

Итак, как я это делаю? Я пробовал плагин knockout.mapping, но это довольно запутанно, и я не заставляю его работать для меня.

Спасибо.

4b9b3361

Ответ 1

Связывание модели ASP.NET MVC будет искать свойства, чувствительные к регистру. Вам нужно передать объект JSON обратно на сервер с именами свойств, соответствующими вашему объекту poco.

Обычно я делаю 1 из 2 вещей:

  • Сделайте свой собственный ресурс имен объектов javascript (таким образом, в JS, я знаю, что этот объект в какой-то момент будет DTO для сервера)

    function Note(date, content, category, color, background) {
        this.Date = date;
        this.Content = content;
        this.Category = category;
        this.Color = color;
        this.Background = background;
    };
    
  • В моем вызове AJAX я просто создаю анонимный объект для передачи обратно на сервер (обратите внимание, что это не требует ko.toJSON):

    $.ajax({
            url: '@Url.Action("AddNote")',
            data: JSON.stringify({ note: {
                    Date: note.date,
                    Content: note.content,
                    Category: note.category,
                    Color: note.color,
                    Background: note.background
                    }
                }),
            type: "post",
            contentType: "application/json; charset=utf-8",
            success: function(result) { }
    });
    

    (обратите внимание и на другой параметр contentType)

Вам нужно сделать свой ActionMethod в (Note note), а не только в массиве параметров.

Кроме того, поскольку модельные узлы просматривают опубликованные значения несколькими способами. Мне посчастливилось опубликовать объекты JSON без указания имени параметра ActionMethod: вместо:

    { note: {
        Date: note.date,
        Content: note.content,
        Category: note.category,
        Color: note.color,
        Background: note.background
        }
    }

просто выполните:

    {
        Date: note.date,
        Content: note.content,
        Category: note.category,
        Color: note.color,
        Background: note.background
    }

(но это может стать рискованным с привязкой массивов к коллекциям и сложным типам... и т.д.)

Что касается "лучшей" сигнатуры для возврата метода, который выполняет вызов db, мы обычно предпочитаем видеть логическое, но это также зависит от ваших потребностей. Очевидно, что если это тривиальные данные, void будет прекрасным, но если он будет более критичным, вы можете захотеть передать логическое (по крайней мере), чтобы ваш клиент знал, что ему может потребоваться повторить попытку (особенно если есть concurrency исключение).

Если вам действительно нужно сообщить своему клиенту, что произошло в базе данных, вы можете выйти в мир пользовательской обработки ошибок и catch > .

Кроме того, если вам нужно отобразить очень конкретную информацию для вашего пользователя в зависимости от успешной/неудачной фиксации базы данных, вы можете посмотреть на создание пользовательских ActionResults, которые перенаправляют к определенным представлениям, основанным на том, что произошло в транзакции базы данных.

Наконец, что касается получения данных с сервера и использования Knockout...

  • снова плагин отображения будет работать, если ваши имена свойств являются одним и тем же случаем или вы создаете несколько более явное сопоставление
  • Мой собственный трюк с моими объектами JS приведен ниже. Функция инициализации - это то, что я создал, которая должна быть повторно использована для всех ваших объектов, поскольку она просто говорит: "Если имена свойств совпадают (после того, как они были уменьшены), либо установите их, вызвав функцию (совместимость с нокаутом), либо просто присвойте значение.:

    function Note(values){ //values are what just came back from the server
        this.date;
        this.content;
        this.category;
        this.color;
        this.background;
    
        initialize(values); //call the prototyped function at the bottom of the constructor
    };
    
    Note.prototype.initialize = function(values){
        var entity = this; //so we don't get confused
            var prop = '';
            if (values) {
                for (prop in values) {
                    if (values.hasOwnProperty(prop.toLowerCase()) && entity.hasOwnProperty(prop.toLowerCase())) {
                        //the setter should have the same name as the property on the values object
    
                        if (typeof (entity[prop]) === 'function') {
                            entity[prop](values[prop]); // we are assuming that the setter only takes one param like a Knockout observable()
                        } else {// if its not a function, then we will just set the value and overwrite whatever it was previously
                            entity[prop] = values[prop];
                        }
                    }
                }
            }
    };