How to bind URL parameters to model properties with different names

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-27 18:04:10

问题


Okay, lets say I have a URL like so, which is mapped via HTTP verb GET to the controller action I have below:

GET /foo/bar?sort=asc&r=true

How can I bind this to my model Bar on my controller action I have below:

class Bar {
    string SortOrder { get; set; }
    bool Random { get; set; }
}

public ActionResult FooBar(Bar bar) {
    // Do something with bar
    return null;
}

Note that the property names won't and can't necessarily match the names of the URL parameters. Also, these are OPTIONAL url parameters.


回答1:


The model binder matches the parameters it gets from the view to the model you have in the action by the Names, so if they won't match the binding will not work.

options you got:

  1. Match the inputs names to the model properties names... but You said you can't do this, (for some unknown reason).
  2. Write custom Model Binder. *
  3. Use The Bind attribute with prefix - though it'll still force you to have input names close to the model properties names.

so basically, You can't do exactly what you want.


Update:

You wrote in a comment that the properties CAN match the parameters names, so instead of write custom attributes that maybe will succeeded to do the binding, just write a ViewModel (The VM fromMVC...) to adjust the url parameters names.

Writing custom model binder is not recommended by the MVC team:

In general, we recommend folks don’t write custom model binders because they’re difficult to get right and they’re rarely needed
from here




回答2:


It's not supported out of the box, but you could do this:

class BarQuery : Bar { 

   public string sort { get { return SortOrder; } set { SortOrder = value; } }
   public bool r { get { return Random; } set { Random = value; } }
}

public ActionResult FooBar(BarQuery bar) {
    // Do something with bar
}

You could implement a custom IModelBinder, but it's much easier to do manual mapping.


If you can change the Bar class you can use this attribute:
class FromQueryAttribute : CustomModelBinderAttribute, IModelBinder { 

   public string Name { get; set; }

   public FromQueryAttribute() { }

   public FromQueryAttribute(string name) { 
      this.Name = name;
   }

   public override IModelBinder GetModelBinder() { 
      return this;
   }

   public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
      return controllerContext.HttpContext.QueryString[this.Name ?? bindingContext.ModelName];
   }
}

class Bar {

    [FromQuery("sort")]
    string SortOrder { get; set; }

    [FromQuery("r")]
    bool Random { get; set; }
}

public ActionResult FooBar(Bar bar) {
    // Do something with bar
    return null;
}



回答3:


I had the same problem a long time ago and used this stack solution by Andras Zoltan: Asp.Net MVC 2 - Bind a model's property to a different named value

I set the ModelBinder attribute on my class and the BindAlias on the property:

  [ModelBinder(typeof(DefaultModelBinderEx))]
  public class MyModel
  {
        [Required]
        [BindAlias("new")]
        public int? Amount { get; set; }

If you can't change or haven't access your model file to set the Attributes, you still can create a custom model binder, OR, make a specific object than you will map to your Model (AutoMapper is usefull)




回答4:


You could implement IModelBinder to map your incoming parameters to the object of your choosing provided the incoming parameter names are defined. Otherwise you would have to rely on parameter order and/or type to infer the proper binding which seems to be a very poor choice.




回答5:


There is no free MVC.Net Modelbinding feature that gives you what you want out of the box. When I need to do something like this, it really makes me think about my modeling which almost always makes me create a ViewModel for my view binding and a EntityModel for my repository storage.

I like to use AutoMapper to convert between these different types. Best part of using AutoMapper is that it drives you away from having to write the mapping logic yourself over and over for each Action in your controller. Just set it up once with AutoMapper in your initialization sections and just execute something like this in the future.

Mapper.Map<Bar>(barViewModel);


来源:https://stackoverflow.com/questions/8507699/how-to-bind-url-parameters-to-model-properties-with-different-names

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!