我使用.NET核心2.我找到了渲染razor视图到字符串的解决方案。较低的MVC版本我已经使用它并且everthing没问题。
我得到结果/形式到bootstrap模态。当我发布到控制器(ex UserName
空值)时,我无法从ModelState获得<span asp-validation-for="UserName" class="text-danger"></span>
的结果,哪里有问题?
当我不使用RenderToStringAsync
方法和return View()
时,我会从ModelState获得<span asp-validation-for="UserName" class="text-danger"></span>
的结果。
始终actionContext
ModelState值或键也为空。
我的服务器端:
public class RazorViewToStringRenderer
{
private readonly IRazorViewEngine viewEngine;
private readonly ITempDataProvider tempDataProvider;
private readonly IHttpContextAccessor _httpContext;
public RazorViewToStringRenderer(
IRazorViewEngine viewEngine,
ITempDataProvider tempDataProvider,
//IServiceProvider serviceProvider,
IHttpContextAccessor httpContext)
{
this.viewEngine = viewEngine;
this.tempDataProvider = tempDataProvider;
_httpContext = httpContext;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var httpContext = _httpContext.HttpContext;
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var sw = new StringWriter())
{
var viewResult = viewEngine.FindView(actionContext, viewName, false);
if (viewResult.View == null)
{
throw new ArgumentNullException($"{viewName} does not match any available view");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(actionContext.HttpContext, tempDataProvider),
sw,
new HtmlHelperOptions()
)
{ RouteData = httpContext.GetRouteData() };
await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}
}
客户端:
@model EditUserViewModel
<form asp-controller="Account" asp-action="EditUser" asp-antiforgery="true" data-ajax-success="onSuccess" data-ajax="true" data-ajax-begin="onBegin" method="post" class="form-horizontal" role="form">
....
<div class="form-group">
<div class="col-sm-12">
<label asp-for="UserName" class="col-form-label"></label>
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div>
</div>
....
</form>
控制器:
[HttpPost]
public async Task<IActionResult> EditUser(EditUserViewModel editUserViewModel)
{
var user = await _userManager.FindByIdAsync(editUserViewModel.Id);
if (user != null)
{
user.UserName = editUserViewModel.UserName;
user.FirstName = editUserViewModel.FirstName;
user.LastName = editUserViewModel.LastName;
var result = await _userManager.UpdateAsync(user);
if (ModelState.IsValid)
{
if (result.Succeeded)
return Json("Ok");
}
else
{
return Json(new
{
ModalClose = false,
Data = _renderer.RenderToStringAsync("EditUser", editUserViewModel)
});
}
}
return RedirectToAction("UserManagement", _userManager.Users);
}
填写结果:
function onSuccess(data, status, xhr)
{
$("#" + modid + " .modal-body").empty();
$("#" + modid + " .modal-body").html(data.data.result);
}
视图模型:
public class EditUserViewModel
{
public string Id { get; set; }
[Display(Name = "User Name")]
[Required(ErrorMessage = "UserName required")]
public string UserName { get; set; }
[Display(Name = "First Name")]
[Required(ErrorMessage = "FirstName required")]
public string FirstName { get; set; }
}
答案 0 :(得分:1)
我已添加到Startup.cs:
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
和
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), _contenxt.ActionContext?.ModelState ?? new ModelStateDictionary())
{
Model = model
};
似乎有效