c# - 在 ASP.Net 5 中渲染 RazorPage 时无法设置模型

标签 c# razor asp.net-core-mvc

我正在使用新的 ASP.Net 5/MVC 6 库构建一个项目,现在我想要将 razor 页面动态呈现为字符串。

这是针对动态小部件系统的,因此我们的想法是在生成模型之后、渲染主视图之前在 ActionFilter 中执行此操作。

它的设置相当大,但主要需要服务并将各个部分组合在一起(如果有人知道更简单的方法,请告诉我们!)。

public override void OnActionExecuted(ActionExecutedContext context) {
    var pageFactory = (IRazorPageFactory)context.HttpContext.ApplicationServices.GetService(typeof(IRazorPageFactory));
    var viewEngine = (IRazorViewEngine)context.HttpContext.ApplicationServices.GetService(typeof(IRazorViewEngine));
    var viewFactory = (IRazorViewFactory)context.HttpContext.ApplicationServices.GetService(typeof(IRazorViewFactory));
    var modelMetadataProvider = (IModelMetadataProvider)context.HttpContext.ApplicationServices.GetService(typeof(IModelMetadataProvider));

    var page = pageFactory.CreateInstance($"~/Views/Widgets/{widgetInfo.Type}.cshtml");
    var view = viewFactory.GetView(viewEngine, page, false);

    var sb = new StringBuilder();
    var sw = new StringWriter(sb);

    page.ViewContext = new ViewContext(new ActionContext(context.HttpContext, context.RouteData, context.ActionDescriptor), view, new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary()), sw);

完成所有这些设置后,我尝试在 ViewData 上设置 Model 属性,我可以看到我已经设置了正确的对象,并且它是页面的正确类型。

    page.ViewContext.ViewData.Model = widgetInfo.Setting;

然后,我执行该页面,当我在模板中未使用任何模型时,该页面效果很好。

    page.ExecuteAsync().GetAwaiter().GetResult();
    sw.Flush();

    var renderedWidget = sb.ToString();

我可以看到我的模板已加载(甚至在其中放置了断点),但模型始终为空。目前我使用这个简单的模板。

@model DataObjects.CodeWidgetModel
@Html.Raw(Model.Code)

我一直在搜索MVC6-sources在 GitHub 上查看我可能错过的内容,但我找不到任何有用的内容。

我正在运行 ASP.Net MVC 6.0.0-beta3-12628KRE 1.0.0-beta3-11014,但很可能会尽快升级到 beta4因为它可用。

任何人都知道为什么在 ViewData 上设置 Model 还不够,或者我还需要做什么才能使其正常工作?

最佳答案

经过更多研究(老实说,经过大量试验和错误),似乎RazorPage.ExecuteAsync()这不是正确的方法。调用RazorView.RenderAsync()相反,正确输入 ViewDataDictionary<>成功了!

下面是最终的代码。

public override void OnActionExecuted(ActionExecutedContext context) {
    var pageFactory = (IRazorPageFactory)context.HttpContext.ApplicationServices.GetService(typeof(IRazorPageFactory));
    var viewEngine = (IRazorViewEngine)context.HttpContext.ApplicationServices.GetService(typeof(IRazorViewEngine));
    var viewFactory = (IRazorViewFactory)context.HttpContext.ApplicationServices.GetService(typeof(IRazorViewFactory));

    var sb = new StringBuilder();
    var sw = new StringWriter(sb);

    var page = pageFactory.CreateInstance($"~/Areas/Widgets/DefaultViews/Widgets/{widgetInfo.Type}.cshtml");
    var view = (RazorView)viewFactory.GetView(viewEngine, page, true);

    var vddType = typeof(ViewDataDictionary<>);
    var vddGeneric = vddType.MakeGenericType(widgetInfo.Model.GetType());
    dynamic viewDataDictionary = Activator.CreateInstance(vddGeneric, new EmptyModelMetadataProvider(), new ModelStateDictionary());

    var actionContext = new ActionContext(context.HttpContext, context.RouteData, context.ActionDescriptor);
    var viewContext = new ViewContext(actionContext, view, viewDataDictionary, sw);
    viewContext.ViewData.Model = widgetInfo.Model;

    view.RenderAsync(viewContext).GetAwaiter().GetResult();
    sw.Flush();

    var renderedWidget = sb.ToString();
}

我对 dynamic 不是特别满意对于 ViewDataDictionary但它有效。可能还有其他更简单的方法可以做到这一点,但目前已经足够了。

ASP.Net MVC 6.0.0-beta3-12628 上测试和KRE 1.0.0-beta3-11014 .

关于c# - 在 ASP.Net 5 中渲染 RazorPage 时无法设置模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29565256/

相关文章:

c# - 如何分解这个r​​eport类呢?

c# - Razor 页面 : Confused about all the return types and when to use them

c# - 具有依赖注入(inject)的 MVC 6 自定义模型绑定(bind)器

C# 使用 FTP 服务器目录填充 TreeView

c# - 使用代码在 Visual Studio 调试控制台中更改颜色

c# - ViewModel 应如何与 Model 通信以使两者同步

c# - JS 中的 Url.Action 不起作用

asp.net - 为什么我的 cookie 设置没有被应用?

c# - 在mvc中获取上传的视频时长

c# - 如何在 ASP.Net MVC 6 中编辑和继续