Renaming ASP.NET MVC 4 Properties for Publishing

Follwing agreements are given. Each Action

has a single type parameter BaseRequest

with data dependent on Action

. ViewModel

always has a type BaseResponse

.

What I'm trying to do is that if a View

contains a form, the POST

-Action requires some sort of BaseRequest

. How can I achieve correct model binding as well ViewModel

- BaseResponse

?

I already tried to add a property XYZRequest

to XYZResponse

so that I can communicate as

@Html.ChecBoxFor(m => m.RequestObject.SomeBooleanProperty)

      

but this will generate a name

RequestObject.SomeBooleanProperty that will not bind correctly to the POST action it takes XYZRequest

.

Is there something completely wrong with these conventions, or am I missing something?

Update # 1

I also tried to create a new temporary

type object XYZRequest

and bind to it like

@Html.CheckBoxFor(m = tmpReq.SomeBooleanProperty)

      

which will display a name

of tmp.SomeBooleanProperty

which also cannot be linked.

Update # 2 - additional information

The following structure is established.

  • BaseRequest

    - abstract

  • GetOverviewRequest

    : BaseRequest

  • GetOverviewRequest

    has properties of a type string

    , int

    or any other complex type, and even Lists

    orDictionaries

If GetOverviewResponse

that inherits from BaseResponse

returns to View

and provides a property named type, communication fails TheProperty

GetOverviewRequest

@Html.TextBoxFor(m => m.TheProperty.SomeBooleanValue)

      

will try to bind to TheProperty

-property on an object GetOverviewRequest

that just doesn't exist.

This can work if it GetOverviewRequest

has a property called TheProperty

for binding. But if it is named differently, the linking will also fail.

I just want something like

<input name="SomeBooleanValue">
<input name="SomeComplexType.SomeStringValue">

      

instead

<input name="TheProperty.SomeBooleanValue">
<input name="TheProperty.SomeComplexType.SomeStringValue">

      

Update # 3 - Added Sample Project

Sample project via dropbox.com

Update # 4 - Explanation why solution from @StephenMuecke doesn't work

As mentioned in the comments, the solution in another question is to know the name of the property in the object GetOverviewResponse

. The property has a name TheProperty

, so I must add [Bind(Prefix = "TheProperty)]

to enable correct binding. I really don't like magic strings. And "TheProperty"

- the magic line. If you change the name TheProperty

to RenamedProperty

, full linking will fail.

So. Now I'm looking for a way to set the prefix in some way dynamically.

[Bind(Prefix = GetOverviewResponse.NameOf(m => m.TheProperty))]

      

it would be really amazing. Maybe some custom attribute? Since the BindAttribute is sealed, there is no way to create an inheritance from this.

Any ideas?

0


source to share


2 answers


As pointed out in the comments, I created a new framework to achieve what I need.

I created a new class BaseRequestWrapperResponse<TRequest>

to encapsulate an object Request

inResponse

    public abstract class BaseRequestWrapperResponse<TRequest> : BaseResponse where TRequest : IRequestFromResponse

      

This class has one property:

    public TRequest Request { get; set; }

      

Next, I created an interface:

    public interface IRequestFromResponse

      



from which my Requset

-object will inherit -> will be used for binding.

In my custom modelbinder override, protected override object CreateModel

I check if (modelType.GetInterfaces().Contains(typeof(IRequestFromResponse)))

to see if my Request

special handling is needed . If so, I dynamically create BindAttribute

and set it before linking normal

does the rest:

                var bindAttribute = new BindAttribute {Prefix = GetPropertyName<BaseRequestWrapperResponse<IRequestFromResponse>, IRequestFromResponse>(r => r.Request)};
            TypeDescriptor.AddAttributes(modelType, bindAttribute);

      

where the GetPropertyName property is defined:

        private static string GetPropertyName<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
    {
        var member = (MemberExpression)propertyLambda.Body;
        return member.Member.Name;
    }

      

See also: Get the name of a property in an abstract generic class

0


source


Binding in MVC works in the Name / Value dictionary. Therefore, if you have:

public class BaseRequest
{
    public string prop1 {get; set;}
    public string prop2 {get; set;}
    public string prop3 {get; set;}
}

      

cshtml:

@Html.TextBoxFor(x => x.prop1)

      

Then the object the controller takes is irrelevant:

public ActionResult MyAction(NotBaseRequest request)
{   
    //do something
}

      

new object taken in:

public class NotBaseRequest
{
    public string prop1 {get; set;}
}

      

MVC will link this with no problem.

So, if you want the child to be bound, you must have a base object in the object that the controller takes:



public class BaseRequest
{
    public NotBaseRequest NotBaseRequest {get; set;}
}

      

cshtml

@Html.TextBoxFor(x => x.NotBaseRequest.prop1)
//<input type="text" name="NotBaseReqest.prop1" value /> 

      

MVC will use the name attribute to send the value to the controller.

controller

public ActionResult MyAction(OtherRequest request)
{
    //do something
}

      

The object you are taking can be called anything as long as it has a NotBaseRequest in it.

new object:

public class OtherRequest
{
    public NotBaseRequest NotBaseRequest {get; set;}
}

      

The name attribute of the html object will create a child object and assign its values.

0


source







All Articles