简体   繁体   中英

Can you make an MVC Post action only accept form data and not querystring

I am using ASP MVC 5 and I have an action on my controller as such

[HttpPost()]
public ActionResult MyMethod(string param)
{
    // Action code here
}

I need this to accept it's data "param" only from form data, and not from a query string.

So something like this should work

<form method="post" action="http://localhost/Home/MyMethod">
    <input type="hidden" name="param" value="MyValue" />
    <input type="submit" value="Post with token" />
</form>

While this should not (happy for this to either not find an action, or find the action by provide an empty model).

<form method="post" action="http://localhost/Home/MyMethod?param=MyValue">
    <input type="submit" value="submit" />
</form>

I've had a bit of a look at a custom model binder

public class FormOnlyModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        /*
         * http://blogs.msdn.com/b/jmstall/archive/2012/04/20/how-to-bind-to-custom-objects-in-action-signatures-in-mvc-webapi.aspx
         * Add [ModelBinder(typeof(FormOnlyModelBinder))] to parameter
         * e.g. public ActionResult RetreiveBill([ModelBinder(typeof(CModelBinder))] string token)
         * In controllerContext.RequestContext.HttpContext.Request you can see the type, and if the data is in q query string or forms data.
         * Just not sure if this is reliable
         */

        throw new NotImplementedException();
     }
}

But don't really know where to go from here, or if this is a reliable way of doing this sort of thing.

The model binding process in MVC takes into account something called Value Providers . These are implementations of the interface IValueProvider and there are a few of them which look at different data sources: FormValueProvider , RouteDataValueProvider , QueryStringValueProvider , HttpFileCollectionValueProvider .

By default the model binding process will take them all into account, but there are ways to restrict which ones will be used.

  • Manually invoke the model binding process specifying which value provider should be used

     public ActionResult MyMethod() { var model = new MyModel(); if (TryUpdateModel(model, new FormValueProvider(this.ControllerContext))) { //proceed with post action } //validation errors, display same form return View(model); } 
  • Add a parameter of type FormCollection to your controller action, and manually invoke the model binding using that parameter as value provider. FormCollection implements IValueProvider by only looking at the form parameters, so it is the same as the option above (but saves you from having to create the value provider instance)

     public ActionResult MyMethod(FormCollection formData) { var model = new MyModel(); if (TryUpdateModel(model, formData)) { //proceed with post action } //validation errors, display same form return View(model); } 
  • Create a model binder that only uses the FormValueProvider as its value provider. This allows you to write the controller action method as you normally would (without having to manually invoke the model binding)

     public class FormOnlyModelBinder: DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { ModelBindingContext newBindingContext = new ModelBindingContext() { ModelMetadata = bindingContext.ModelMetadata, ModelName = bindingContext.ModelName, ModelState = bindingContext.ModelState, PropertyFilter = bindingContext.PropertyFilter, FallbackToEmptyPrefix = bindingContext.FallbackToEmptyPrefix, ValueProvider = new FormValueProvider(controllerContext), }; return base.BindModel(controllerContext, newBindingContext); } } 

All these options will have the same effect. I would use the second option only if I had this requirement on a very particular action, in any other case I would probably use the custom model binder.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM