问题
Is there a way to cast parameter in the controller's action from one type to another in ASP.NET MVC 5?
Example. Action method is the following:
public string Test(Guid input) {
return "";
}
If the method is invoked with parameters "input=hello" then I get the error with the message: "The parameters dictionary contains a null entry for parameter 'input' of non-nullable type 'System.Guid' for method 'System.String Test(System.Guid)' in 'RealtyGuide.WebSite.Controllers.HomeController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
What I want is try to cast the parameter to Guid according to specific (custom) rules. Is it a question on model binding? What are the possible ways to solve this task? Sorry for my English.
About the answers. If you just want assign null to a Guid parameter if it is invalid, then look at this answer. If you are looking for an example of custom model binder, then look at this and this answers.
回答1:
in reply to Hoborg's example, https://stackoverflow.com/posts/26676337/revisions the following will return null values or the Guid parameter, if it is desired.
public class NullableGuidBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(Guid?))
{
var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
string input = valueResult.AttemptedValue;
if (string.IsNullOrEmpty(input) || input == "0")
{
// return null, even if input = 0
// however, that is dropdowns' "guid.empty")
// base.BindModel(...) would fail converting string to guid,
// Guid.Parse and Guid.TryParse would fail since they expect 000-... format
// add the property to modelstate dictionary
var modelState = new ModelState { Value = valueResult };
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return null;
}
}
return base.BindModel(controllerContext, bindingContext);
}
}
binding as follows in your controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SelectAction(
[ModelBinder(typeof(NullableGuidBinder))] Guid? id)
{
// your stuff
}
回答2:
According to the comments from @AndreiV and @AntP the decisions are:
if the string is a correct Guid-string then it is binded automatically (nothing else is needed),
if the string is not a correct Guid-string one should
2.1. make conversion in the action's body (to my mind it entails code duplication), or
2.2. set up the custom (user-defined) model binder. The following is the code for the last approach (model binder).
// This is an example.
// Note the returning of null which is undesired.
// Also it does not deal with exceptions handling. Use it only as a stub.
public class ExtendedModelBinder : DefaultModelBinder {
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
if (!(bindingContext.ModelType == typeof(Guid)))
return base.BindModel(controllerContext, bindingContext);
if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
return null;
string input = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;
if (string.IsNullOrEmpty(input))
return null;
Guid g;
if (Guid.TryParse(input, out g))
return g;
var bytes = HttpServerUtility.UrlTokenDecode(s);
var result = new Guid(bytes);
return result;
}
}
Registration in Application_Start is necessary:
ModelBinders.Binders.Add(typeof(Guid), new RealtyGuide.WebSite.Extensions.MyModelBinder());
One may use attributes instead of registration of the binder globally (see here), but I'll not use it, because it entails unnecessary code duplication in my task.
Refs: 1, 2, 3
回答3:
I have stumbled upon this question when searching about Guid
binding in action with a graceful fallback when the value is not valid. If the actual provided value does not have to be known, using a nullable Guid
(Guid?
) should to the trick. E.g. (this is tested in ASP.NET Web API):
[Route("Test")]
[HttpGet]
public string Test(Guid? input = null)
If a valid Guid
is provided, input will be populated. Otherwise, it will be null
.
回答4:
Trying input="helo" is an wrong method. Guid must contain 32 bit number value example (12345678910111213141516171819202)
Try this input = 12345678910111213141516171819202, By giving value like 32 digit number the Guid value accepts it. then the the method will not display the same error.
var input = 12345678910111213141516171819202;
public string Test(Guid input) {
return "";
}
来源:https://stackoverflow.com/questions/26673881/asp-net-mvc-types-cast-in-model-binding