更新模型时使用 HtmlString 会引发 InvalidOperationException

Posted

技术标签:

【中文标题】更新模型时使用 HtmlString 会引发 InvalidOperationException【英文标题】:Using HtmlString throws an InvalidOperationException when updating the model 【发布时间】:2012-07-08 18:33:22 【问题描述】:

我正在像这样在我的模型上使用 htmlString 属性

public HtmlString Html  get; set; 

然后我有一个可以呈现的 EditorTemplate 和 html 编辑器,但是当我使用 TryUpdateModel() 时,我得到一个 InvalidOperationException,因为没有类型转换器可以在这些类型 String 和 HtmlString 之间进行转换。

我需要创建自定义模型绑定器还是有其他方法?

更新:

我正在尝试在我的模型上使用 HtmlString,主要是为了让它明显包含 HTML。 所以这就是我的完整模型的样子:

public class Model 
    public HtmlString MainBody  get; set; 

这就是我呈现表单的方式:

@using (Html.BeginForm("save","home"))
    @Html.EditorForModel()
    <input type="submit" name="submit" />

我创建了自己的编辑器模板,名为 Object.cshtml,以便可以将 MainBody 字段呈现为文本区域。

我的控制器有一个如下所示的 Save 方法:

public void Save([ModelBinder(typeof(FooModelBinder))]Model foo) 
    var postedValue = foo.MainBody;

如您所见,我一直在使用如下所示的自定义模型绑定器:

public class FooModelBinder : DefaultModelBinder 
    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) 
        if (propertyDescriptor.PropertyType == typeof(HtmlString)) 
            return new HtmlString(controllerContext.HttpContext.Request.Form["MainBody.MainBody"]);
        
        return null;
    

这按预期工作,但我不知道如何从 bindingContext 获取完整的 ModelName,因为 bindingContext.ModelName 只包含 MainBody 而不是 MainBody.MainBody?

我也对其他解决方案感兴趣,或者如果有人认为这是一个非常糟糕的主意。

【问题讨论】:

【参考方案1】:

我是否需要创建自定义模型绑定器

是的,如果您想在视图模型上使用 HtmlString 属性,因为此类没有无参数构造函数,并且默认模型绑定器不知道如何实例化它。

或者还有其他方法吗?

是的,不要在视图模型上使用HtmlString 属性。可能还有其他方法。不幸的是,由于您提供了关于您的上下文以及您想要实现的确切目标的严格 0 信息,因此到目前为止我们可以为您提供帮助。


更新:

现在您已经展示了一小部分代码,这里是一个示例。

型号:

public class Model

    public HtmlString MainBody  get; set; 

控制器:

public class HomeController : Controller

    public ActionResult Index()
    
        return View(new Model());
    

    [HttpPost]
    public ActionResult Index([ModelBinder(typeof(FooModelBinder))]Model foo)
    
        var postedValue = foo.MainBody;
        return Content(postedValue.ToHtmlString(), "text/plain");
    

模型绑定器:

public class FooModelBinder : DefaultModelBinder

    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
    
        if (propertyDescriptor.PropertyType == typeof(HtmlString))
        
            return new HtmlString(bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue);
        
        return null;
    

查看(~/Views/Home/Index.cshtml):

@using (Html.BeginForm())

    @Html.EditorForModel()
    <input type="submit" name="submit" />

自定义对象编辑器模板以便深入了解 (~/Views/Shared/EditorTemplates/Object.cshtml):

@foreach (var property in ViewData.ModelMetadata.Properties.Where(x => x.ShowForEdit))

    if (!string.IsNullOrEmpty(property.TemplateHint))
    
        @Html.Editor(property.PropertyName, property.TemplateHint)
    
    else
    
        @Html.Editor(property.PropertyName)
    

HtmlString 类型的自定义编辑器模板将呈现为文本区域 (~/Views/Shared/EditorTemplates/HtmlString.cshtml):

@Html.TextArea("")

顺便说一句,我仍然不明白你为什么要使用 HtmlString 作为属性而不是简单的字符串。

【讨论】:

我看不出你错过了什么样的信息。我有一个带有属性 HtmlString 的模型,我正在使用 Html.EditorForModel 呈现表单,并将表单发布到控制器,我希望它绑定我的 HtmlString 的值,以便我可以保留我的对象。这在我的书中很简单。我会在白天更新我的问题,感谢您的宝贵时间。 @Marcus,我已经更新了我的答案,试图为您提供一个完整的例子。 太好了,效果很好!我想使用 HtmlString 作为属性的原因是因为我正在开发一个 CMS,我认为在字符串上使用 HtmlString 更合适,因为在我的编辑模式下,HtmlString 将呈现一个像 TinyMCE 这样的 HTML 编辑器,因此它包含 HTML 其中 HtmlString表示。 太好了,您还有其他问题吗?或者您可以考虑关闭此主题?

以上是关于更新模型时使用 HtmlString 会引发 InvalidOperationException的主要内容,如果未能解决你的问题,请参考以下文章

android:targetSdkVersion更新引发的“惨案”

在 python inotify 中未引发 IN_Q_OVERFLOW 事件

在运行时更新 PNG 图像会引发 GDI+ 溢出异常

MS Access“更新后”事件:引发错误

PUT 方法在表单中不起作用会引发错误

ValueError: feature_names mismatch: in xgboost in the predict() function