1

Is there a way/builtin solution to map a query string property to a .NET property?

For a Action and model:

public ActionResult Index(AuthInitialRequest request)
{
    return View(request);
}

public class AuthInitialRequest
{
     [Required]
     public string FooBar { get; set; }
     ...
}

What i want to achieve is functionality similar to JsonProperty attribute. Which will map model property to query attribute based on attribute.

public class AuthInitialRequest
{
     [Required]
     [QueryStringProperty("foo-bar")
     public string FooBar { get; set; }
     ...
}
ArunPratap
  • 4,816
  • 7
  • 25
  • 43
  • 1
    Have a look at [How to bind URL parameters to model properties with different names](https://stackoverflow.com/questions/8507699/how-to-bind-url-parameters-to-model-properties-with-different-names?lq=1) – mmushtaq Apr 24 '19 at 07:25

1 Answers1

1

Thanks mmushtaq for keep me on track. BindAliasAttribute allows to set multiple alias name for our model

public class AliasModelBinder : DefaultModelBinder
{
    protected override PropertyDescriptorCollection
      GetModelProperties(ControllerContext controllerContext,
                        ModelBindingContext bindingContext)
    {
        var toReturn = base.GetModelProperties(controllerContext, bindingContext);

        List<PropertyDescriptor> additional = new List<PropertyDescriptor>();

        //now look for any aliasable properties in here
        foreach (var p in
          this.GetTypeDescriptor(controllerContext, bindingContext)
          .GetProperties().Cast<PropertyDescriptor>())
        {
            foreach (var attr in p.Attributes.OfType<BindAliasAttribute>())
            {
                additional.Add(new AliasedPropertyDescriptor(attr.Alias, p));

                if (bindingContext.PropertyMetadata.ContainsKey(p.Name))
                    bindingContext.PropertyMetadata.Add(attr.Alias,
                          bindingContext.PropertyMetadata[p.Name]);
            }
        }

        return new PropertyDescriptorCollection
          (toReturn.Cast<PropertyDescriptor>().Concat(additional).ToArray());
    }
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class BindAliasAttribute : Attribute
{
    public BindAliasAttribute(string alias)
    {
        Alias = alias;
    }

    public string Alias { get; private set; }

    public override object TypeId
    {
        get { return Alias; }
    }
}
internal sealed class AliasedPropertyDescriptor : PropertyDescriptor
{
    public PropertyDescriptor Inner { get; private set; }
    public AliasedPropertyDescriptor(string alias, PropertyDescriptor inner)
        : base(alias, null)
    {
        Inner = inner;
    }
    public override bool CanResetValue(object component)
    {
        return Inner.CanResetValue(component);
    }
    public override Type ComponentType
    {
        get { return Inner.ComponentType; }
    }
    public override object GetValue(object component)
    {
        return Inner.GetValue(component);
    }
    public override bool IsReadOnly
    {
        get { return Inner.IsReadOnly; }
    }
    public override Type PropertyType
    {
        get { return Inner.PropertyType; }
    }
    public override void ResetValue(object component)
    {
        Inner.ResetValue(component);
    }
    public override void SetValue(object component, object value)
    {
        Inner.SetValue(component, value);
    }
    public override bool ShouldSerializeValue(object component)
    {
        return Inner.ShouldSerializeValue(component);
    }
}

And attribute defined like so can be used like this:

[Required]
[BindAlias("original-url")]
public string Original_Url { get; set; }