Десериализация JSON для объекта без конструктора по умолчанию в ASP.NET MVC 3 - PullRequest
4 голосов
/ 09 сентября 2011

Существует довольно много вопросов относительно десериализации JSON, но многие из них, похоже, относятся к MVC 1 или MVC 2. Похоже, я не нашел удовлетворительного ответа на этот вопрос специально для MVC 3.

У меня есть объект с неизменяемыми свойствами и без конструктора по умолчанию, который я хочу десериализовать в приложении ASP.NET MVC 3.Вот упрощенная версия:

public class EmailAddress
{
    public EmailAddress(string nameAndEmailAddress)
    {
        Name = parseNameFromNameAndAddress(nameAndEmailAddress);
        Address = parseAddressFromNameAndAddress(nameAndEmailAddress);
    }

    public EmailAddress(string name, string address)
    {
        Guard.Against<FormatException>(!isNameValid(name), "Value is invalid for EmailAddress.Name: [{0}]", name);
        Guard.Against<FormatException>(!isAddressValid(address), "Value is invalid for EmailAddress.Address: [{0}]", address);
        Name = name;
        Address = address;
    }

    public string Address { get; private set; }
    public string Name { get; private set; }

    // Other stuff
}

Примером действия контроллера может быть:

[HttpPost]
public ActionResult ShowSomething(EmailAddress emailAddress)
{
    return View(emailAddress)
}

Входит JSON:

{"Address":"joe@bloggs.com","Name":"Joe Bloggs"}

Что лучшеспособ получить это для десериализации в MVC3?Есть ли какой-нибудь способ реализации пользовательского связывателя модели или класса десериализатора, который может это обработать?

Было бы предпочтительным решение, которое не мешает самому объекту (т. Е. Отдельный класс десериализатора, а не добавление атрибутов).свойствам и т. д.), хотя открыты для любых хороших предложений.

Я нашел похожий вопрос (без ответа) здесь: Можно ли десериализовать неизменный объект с помощью JavascriptSerializer?

Ответы [ 2 ]

6 голосов
/ 09 сентября 2011

Есть ли какой-нибудь способ реализации пользовательского связующего для модели или класс десериализатора, который может справиться с этим?

Да, вы можете написать связующее для пользовательской модели:

public class EmailAddressModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var addressKey = "Address";
        var nameKey = "Name";
        if (!string.IsNullOrEmpty(bindingContext.ModelName))
        {
            addressKey = bindingContext.ModelName + "." + addressKey;
            nameKey = bindingContext.ModelName + "." + nameKey;
        }

        var addressValue = bindingContext.ValueProvider.GetValue(addressKey);
        var nameValue = bindingContext.ValueProvider.GetValue(nameKey);
        if (addressValue == null || nameValue == null)
        {
            throw new Exception("You must supply an address and name");
        }
        return new EmailAddress(nameValue.AttemptedValue, addressValue.AttemptedValue);
    }
}

, который будет зарегистрирован в Application_Start:

ModelBinders.Binders.Add(typeof(EmailAddress), new EmailAddressModelBinder());

и, наконец, все, что осталось, это вызвать действие:

$.ajax({
    url: '@Url.Action("ShowSomething")',
    type: 'POST',
    data: JSON.stringify({ "Address": "joe@bloggs.com", "Name": "Joe Bloggs" }),
    contentType: 'application/json',
    succes: function (result) {
        alert('success');
    }
});
0 голосов
/ 09 сентября 2011

ИЗМЕНЕННЫЙ ОТВЕТ:

Я неправильно прочитал код, посмотрел на параметры конструктора, а не на свойства.

Причина вашей проблемы - закрытый набор свойств.

Т.е. должно быть:

public string Address { get; set; }
public string Name { get; set; }

Если вы сделаете это изменение, все должно работать.

Просто запомните:

Связыватель модели ищет СВОЙСТВА, а не конструктор!

...