R – Invaid cast exception, even when I have an implicit cast operator defined (in asp mvc app)

asp.net-mvcasp.net-mvc-2implicit-conversion

I have an mvc model class created and one of the properties is of type 'MyObject'. It also has a System.ComponentModel.DataAnnotations.StringLength attribute on it.

MyObject as implicit cast operators so it can essentially be used as a string:

public static implicit operator string(MyObject o){...}
public static implicit operator MyObject(string sValue){...}

Is this an asp mvc issue for some strange reason? I ask because I know in most cases the implicit cast works fine, I can for example assign that property to a string value and it works just fine.

Edit – Ok, I know why the error is occuring:
It's because the StringLength.IsValid() method takes an object as a parameter, so the cast is actually going from object to string, not from MyObject to string, so that explains why my implicit cast operator is not being called. But how to work around this?

This all worked fine until I put the System.ComponentModel.DataAnnotations.StringLength attribute on the property in my model, then when the view does a post from a submit button, I got the exception:

[InvalidCastException: Unable to cast
object of type
'StrataSpot.Shared.Models.Email' to
type 'System.String'.]
System.ComponentModel.DataAnnotations.StringLengthAttribute.IsValid(Object
value) +34
System.Web.Mvc.d__1.MoveNext()
+56 System.Web.Mvc.DefaultModelBinder.OnPropertyValidated(ControllerContext
controllerContext, ModelBindingContext
bindingContext, PropertyDescriptor
propertyDescriptor, Object value) +203
System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext
controllerContext, ModelBindingContext
bindingContext, PropertyDescriptor
propertyDescriptor) +413
System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext
controllerContext, ModelBindingContext
bindingContext) +90
System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext
controllerContext, ModelBindingContext
bindingContext, Object model) +383
System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext
controllerContext, ModelBindingContext
bindingContext) +1048
System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext
controllerContext, ModelBindingContext
bindingContext) +280
System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext
controllerContext, ParameterDescriptor
parameterDescriptor) +257
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext
controllerContext, ActionDescriptor
actionDescriptor) +109
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext
controllerContext, String actionName)
+314 System.Web.Mvc.Controller.ExecuteCore()
+105 System.Web.Mvc.ControllerBase.Execute(RequestContext
requestContext) +39
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext
requestContext) +7
System.Web.Mvc.<>c__DisplayClass8.b__4()
+34 System.Web.Mvc.Async.<>c__DisplayClass1.b__0()
+21 System.Web.Mvc.Async.<>c__DisplayClass81.<BeginSynchronous>b__7(IAsyncResult
_) +12 System.Web.Mvc.Async.WrappedAsyncResult
1.End()
+59 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult
asyncResult) +44
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult
result) +7
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
+8678910 System.Web.HttpApplication.ExecuteStep(IExecutionStep
step, Boolean& completedSynchronously)
+155

Best Answer

You can't use [StringLength] for a property of a type other than String. If you want to duplicate the functionality, you can subclass StringLengthAttribute:

public class MyCoolAttribute : StringLengthAttribute {
  // constructor here

  public override bool IsValid(object value) {
    return base.IsValid((string)(value as MyObject));
  }
}

Then slap [MyCool] instead of [StringLength] on your property. Using a cast operator in this regard probably isn't the cleanest thing in the world; you should probably use ToString() or something similar instead. But the idea is the same.

Alternatively, if you don't want to subclass StringLengthAttribute, you can just delegate to a private StringLengthAttribute instance's IsValid() method instead.

Related Topic