ASP.NET MVC с Spring.NET и ModelBinder
-
29-08-2019 - |
Вопрос
Я работаю над демонстрацией, в которой используются возможности Spring.NET IoC в ASP.NET MVC.Это что-то вроде приложения MyBlog, представленного в видеоуроке по парному программированию на сайте www.asp.net.Я выполнил ту же демонстрацию, используя платформу Microsoft Unity, и теперь хочу опробовать контейнер Spring.С этой целью я реализовал простой IControllerFactory, который сначала создает фабрику объектов Spring следующим образом:
IObjectFactory factory;
(....)
factory = new XmlObjectFactory(new FileSystemResource(application.Server.MapPath("objects.xml")))
и затем он получает контроллер с этой фабрики следующим образом:
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) {
IController result = context.GetObject(controllerName) as IController;
return result;
}
(обработка ошибок удалена для упрощения).
Теперь где-то в моем HomeController у меня есть такое действие:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddEntry([Bind] BlogEntry entry, int id) {
entry.EntryDate = DateTime.Now;
....
А вот часть представления AddEntry.aspx, которая определяет редакторы для параметра ввода (действительно базовые вещи):
<form method="post" action="/Home/AddEntry/<%= ViewData["id"] %>">
<table>
<tr>
<td><label for="Title">Title</label></td>
<td><input name="entry.Title" type="text"/></td>
</tr>
<tr>
<td><label for="Text">Content</label></td>
<td><input name="entry.Text" type="text"/></td>
</tr>
</table>
<br />
<input type="submit" value="Add entry" />
<input type="button" value="Cancel" onclick="history.back(-1);" />
</form>
Теперь вот сделка:Когда я использую Unity IoC, он работает как шарм.Параметр «entry» десериализуется из моей формы, как и должно быть, и строка
entry.EntryDate = DateTime.Now;
завершается без проблем.
Однако когда я переключаюсь на фабрику объектов Spring.NET (как описано выше), все начинает идти наперекосяк.Прежде всего, параметр «entry» становится нулевым, поэтому генерируется исключение.Чтобы отследить возможную проблему с моей стороны, я реализовал своего рода собственный IModelBinder, который выглядит следующим образом:
public class BlogEntryBinder : IModelBinder {
public ModelBinderResult BindModel(ModelBindingContext bindingContext) {
ModelBinderResult result = ModelBinders.DefaultBinder.BindModel(bindingContext);
return result;
}
}
Когда я прихожу сюда, используя платформу Unity, и углубляюсь от привязкиконтекста к HttpRequest, я вижу, что Request.HttpMethod имеет значение «POST», а Request.Form правильно заполнен.Когда я делаю то же самое, используя Spring.NET, метод «GET», а Request.Form пуст.Однако когда я перехожу к действию моего контроллера (AddEntry) и углубляюсь в запрос в обеих ситуациях, я вижу, что Request.HttpMethod и Request.Form имеют правильные значения.
Теперь вопрос в том, как исправить версию с Spring.NET, чтобы она работала так же, как та, которая использует платформу Unity?
Решение
Я нашел ответ!
Мое определение объекта выглядело так:
<!-- Controlers -->
<object name="Home" type="MyBlog.Controllers.HomeController">
<property name="BlogService" ref="BlogService" />
<property name="BlogEntryService" ref="BlogEntryService" />
<property name="BlogEntryCommentService" ref="BlogEntryCommentService" />
</object>
Не говоря уже о том, что свойства устанавливаются, на самом деле они возвращают один и тот же экземпляр каждый раз, когда я запрашиваю этот объект, используя
IController result = context.GetObject(controllerName) as IController;
Поэтому, когда я изменил определение на
<!-- Controlers -->
<object name="Home" type="MyBlog.Controllers.HomeController" singleton="false">
<property name="BlogService" ref="BlogService" />
<property name="BlogEntryService" ref="BlogEntryService" />
<property name="BlogEntryCommentService" ref="BlogEntryCommentService" />
</object>
все стало работать нормально.
С уважением, Матиас.
Другие советы
просто дополнительное примечание для пояснения этого поведения:Платформа ASP.NET MVC рассматривает контроллеры как прототипы, но Spring по умолчанию использует одноэлементный режим.Поэтому вам необходимо явно пометить ваш объект как неодноэлементный в конфигурации контейнера.Об этом позаботится предстоящий модуль интеграции Spring MVC, так что вы с этим не столкнетесь.
HTH, Эрих