Using HtmlString throws an InvalidOperationException when updating the model

I'm using an HtmlString property on my model like this

public HtmlString Html { get; set; }

then I have an EditorTemplate that renders and html editor but when I use TryUpdateModel() I get an InvalidOperationException because no type converter can convert between these types String and HtmlString.

Do I need to create a custom model binder or is there another way?

UPDATE:

I'm trying to use HtmlString on my model, mostly for making it obvious that it contains HTML. So this is what my complete model looks like:

public class Model {
    public HtmlString MainBody { get; set; }
}

and this is how I render the form:

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

I have created my own editor template called Object.cshtml so that the field MainBody can be rendered as a textarea.

My controller has a Save method that looks like this:

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

As you can see I have been playing around with a custom model binder that looks like this:

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;
    }
}

this works as expected but I don't know how to get the complete ModelName from the bindingContext because bindingContext.ModelName only contains the MainBody and not MainBody.MainBody?

I'm also interested in other solutions regarding this or maybe if someone thinks it's a really bad idea.

Answers


Do I need to create a custom model binder

Yes, if you want to use an HtmlString property on your view model because this class has no parameterless constructor and the default model binder has no clue how to instantiate it.

or is there another way?

Yes, don't use HtmlString property on the view model. There might also be other ways. Unfortunately since you have provided strictly 0 information about your context and what precisely you are trying to achieve that's all we could help you with so far.


UPDATE:

Now that you have shown a wee-bit of your code here's a sample.

Model:

public class Model
{
    public HtmlString MainBody { get; set; }
}

Controller:

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");
    }
}

Model binder:

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;
    }
}

View (~/Views/Home/Index.cshtml):

@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" name="submit" />
}

Custom object editor template in order to do a deep dive (~/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)
    }
}

Custom editor template for the HtmlString type to be rendered as a textarea (~/Views/Shared/EditorTemplates/HtmlString.cshtml):

@Html.TextArea("")

By the way I still don't understand why you would want to use HtmlString as a property instead of a simple string but anyway.


Need Your Help

Ionic : how to deeply customize ion-toggle?

css ionic toggle ion-toggle

Within Ionic, I am trying to customize &lt;ion-toggle&gt; but I face an issue of toggle selection in css.

VS2010 Not Always Building Before Debugging

debugging visual-studio-2010

I have had a problem where VS2010 will not build my projects before debugging. Even when they have never been built before (i.e. on a fresh checkout from source control).