Как обрабатывать форму сообщения из View Component (Razor Core 2)
В эти выходные много борьбы с View Component.
Я пытаюсь добавить выпадающий список, который выполняет автоматическую замену обратной передачи. Этот выпадающий список находится на компоненте представления.
У меня 2 проблемы:
- Я не получаю asp-page-handler после поста, работает ли он так, как я его реализовал в теге form?
- Опубликовать вызов метода public void OnPost на странице бритвы, содержащей компонент вида. Я думаю, что было бы лучше иметь метод на компонент View, как OnChangeProject?
Код моего просмотра (View Component):
<form asp-page-handler="ChangeProject" method="post">
@Html.AntiForgeryToken()
@Html.DropDownList("id", new SelectList(Model, "Id", "Id"), new { onchange = "this.form.submit()" })
</form>
Заранее спасибо!!
4 ответа
Я испытал ту же проблему, и способ, которым я исправил это, уже ответил на Ваш вопрос.
Вызов формы выполняется на странице, где вы встроили свой View View. Я не думаю, что было бы даже возможно вызвать обработчик в вашем компоненте просмотра с asp-page-handler
так как это хелпер тегов Razor Pages.
То, как я это получил, - это просто положить метод обработчика страниц на PageModel
это вложение компонента View. В вашем случае вы можете просто реализовать этот обработчик на своей странице Razor:
public IActionResult OnPostChangeProject()
{
// ... do Something
}
Я не знаю, хотя, как это будет работать, чтобы вызвать метод контроллера в вашем компоненте просмотра. Возможно, создайте новый класс Controller и направьте его asp-controller
а также asp-action
в вашей форме тега.
Вы должны помнить, что обработчики Page можно рассматривать как удобные методы. Все, что делает платформа ASP.Net Core, — это просмотр параметров строки запроса и данных формы и преобразование их в вызовы обработчика страниц. И даже несмотря на то, что обработчики недоступны в компонентах представления или частичных представлениях, вы все равно можете получить доступ ко всем необходимым ингредиентам, внедривIHttpContextAccessor
в Представление. Он предоставит вамHttpContext.Request
который содержит какQuery
иForm
характеристики.
Затем вы можете создать свой собственный преобразователь Handler. Вот один, например:
public class HandlerMapping
{
public string Name { get; set; }
public System.Delegate RunDelegate { get; set; }
public HandlerMapping(string name, Delegate runDelegate)
{
RunDelegate = runDelegate;
Name = name;
}
}
public class PartialHandlerMapper
{
IHttpContextAccessor _contextAccessor;
public PartialHandlerMapper(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public void RouteHandler(List<HandlerMapping> handlerMappings, string PartialDescriminatorString = null)
{
var handlerName = _contextAccessor.HttpContext.Request.Query["handler"];
var handlerMapping = handlerMappings.FirstOrDefault(x => x.Name == handlerName);
if (handlerMapping != null)
{
IFormCollection form;
try
{
form = _contextAccessor.HttpContext.Request.Form;
}
catch
{
return;
}
if (!string.IsNullOrWhiteSpace(PartialDescriminatorString) && form[nameof(PartialDescriminatorString)] != PartialDescriminatorString)
return;
List<Object> handlerArgs = new List<object>();
var prmtrs = handlerMapping.RunDelegate.Method.GetParameters();
foreach (var p in prmtrs)
{
object nv = null;
var formValue = form[p.Name];
if (!StringValues.IsNullOrEmpty(formValue))
{
try
{
nv = TypeDescriptor.GetConverter(p.ParameterType).ConvertFromString(formValue);
}
catch (FormatException)
{
//throw new FormatException($"Could not cast form value '{formValue}' to parameter {p.Name} (type {p.ParameterType}) of handler {handlerName}. Make sure you use correct type parameter. ");
nv = Activator.CreateInstance(p.ParameterType);
}
catch (ArgumentException)
{
nv = Activator.CreateInstance(p.ParameterType);
}
}
else
nv = Activator.CreateInstance(p.ParameterType);
handlerArgs.Add(nv);
}
handlerMapping.RunDelegate.DynamicInvoke(handlerArgs.ToArray());
}
}
}
И внедрить его в сервисный контейнер:
services.AddScoped<PartialHandlerMapper>();
А вот пример раздела кода частичного просмотра корзины:
@inject ShoppingManager shoppingManager
@inject PartialHandlerMapper partialHandlerMappping
@{
string ToggleCartItemTrialUseHandler = nameof(ToggleCartItemTrialUseHandler);
string DeleteCartItemHandler = nameof(DeleteCartItemHandler);
List<HandlerMapping> handlerMappings = new List<HandlerMapping> {
new HandlerMapping (ToggleCartItemTrialUseHandler, (Guid? PicID, bool? CurrentValue) => {
if (PicID == null || CurrentValue == null)
return;
shoppingManager.UpdateTrial((Guid)PicID, !(bool)CurrentValue);
}),
new HandlerMapping (DeleteCartItemHandler, (Guid? PicID) => {
if (PicID == null)
return;
shoppingManager.RemoveProductFromCart((Guid)PicID);
})
};
partialHandlerMappping.RouteHandler(handlerMappings);
var cart = shoppingManager.GetSessionCart();
}
Пример элемента формы из того же представления:
<td align="center" valign="middle">
<form asp-page-handler="@DeleteCartItemHandler">
<input name=PicID type="hidden" value="@i.PicID" />
<button>
Delete
</button>
</form>
</td>
Где @i — товар в корзине
Есть похожий вопрос о частичных взглядах. Почему обработчик частичного просмотра не запускается при обратной передаче. Не удается найти подходящее объяснение или статью, которая четко объясняет это. Форма частичного просмотра
Можно создать комбо (Контроллер /ViewComponent), украсив контроллер ViewComponent(Name="myviewcomponent").
Затем создайте invokeasync как обычно, но поскольку контроллер не наследуется от ViewComponent, возвращаемый результат будет одним из результатов ViewComponent (ViewViewComponentResult, et).
Форма в компоненте представления может иметь кнопку с помощниками тегов asp-controller/action, нацеленными на контроллер / действие.