2

I don't know if this is the right way of doing this or not, but I am using Jquery and MVC2. I am using a the $.ajax method to make a call back to a controller to do some business logic on a .blur of a textbox.

I have two views that basically do the same thing with the common data, but are using different models. They both use the same controller. It might be easier to explain with code:

So here are the two models:

public class RecordModel {
    public string RecordID { get; set; }
    public string OtherProperties { get; set; }
}

public class SecondaryModel {
    public string RecordID { get; set; }
    public string OtherPropertiesDifferentThanOtherModel { get; set; }
}

There are two views that are strongly typed to these models. One is RecordModel, the other SecondaryModel.

Now on these views is a input="text" that is created via:

<%= Html.TextBoxFor(model => model.RecordID) %>

There is jQuery javascript that binds the .blur method to a call:

<script>
    $('#RecordID').blur(function() {
        var data = new Object();
        data.RecordID = $('#RecordID').val();
        // Any other stuff needed

        $.ajax({
            url: '/Controller/ValidateRecordID',
            type: 'post',
            dataType: 'json',
            data: data,
            success: function(result) {
                 alert('success: ' + result);
            },
            error: function(result) {
                 alert('failed');
            }
         });
      }
 </script>

The controller looks like:

[HttpPost]
public ActionResult ValidateRecordID(RecordModel model) {
    // TODO: Do some verification code here

    return this.Json("Validated.");
}

Now this works fine if I explicitly name the RecordModel in the controller for the View that uses the RecordModel. However, the SecondaryModel view also tries to call this function, and it fails because it's expecting the RecordModel and not the SecondaryModel.

So my question is this. How can two different strongly typed views use the same Action in a controller and still adhering to the modeling pattern? I've tried abstract classes and interfaces (and changing the view pages to use the Interface/abstract class) and it still fails.

Any help? And sorry for the robustness of the post...

Thanks.

Sean
  • 2,496
  • 7
  • 32
  • 60
  • 1
    If the validation process is different for RecordModel and SecondaryMOdel, why the need to use the same action on controller? – Chandu Jan 26 '11 at 19:17
  • No the validation method is the same. The models are different on different views using the same controller. – Sean Jan 26 '11 at 20:51
  • Why not just take a string RecordID as the parameter then, you aren't passing anything else anyway. – Jason Goemaat Jan 27 '11 at 05:11
  • This is what I ended up doing. I was just curious if there was a way to do it the way I mentioned above. – Sean Jan 27 '11 at 16:41

4 Answers4

1

You could define an interface for those classes.

interface IRecord
{
    string RecordID { get; set; }
    string OtherProperties { get; set; }
}

and make the method receive the model by using that:

[HttpPost]
public ActionResult ValidateRecordID(IRecord model) 
{
    // TODO: Do some verification code here

    return this.Json("Validated.");
}
Ufuk Hacıoğulları
  • 37,978
  • 12
  • 114
  • 156
  • The ViewPage inherits changes from: System.Web.Mvc.ViewPage to System.Web.Mvc.ViewPage? – Sean Jan 26 '11 at 20:50
  • The error I'm getting when using this method is that the "other property's" Html.TextBox(model => model.OtherProperty) isn't part of the Models.IRecord (it is part of RecordModel, but not SecondaryModel). 'Models.IRecord' does not contain a definition for 'OtherProperty' and no extension method 'OtherProperty' accepting a first argument of type 'Models.IRecord' could be found – Sean Jan 26 '11 at 20:54
  • When using the RecordModel and the SecondaryModel, the only common property the two have are the RecordID. All the other properties are completely different for each model. I was just trying to find a common way to call the same Action from two different Views that use the same controller but with two different models (or many models for that matter). – Sean Jan 26 '11 at 21:10
  • You can keep seperate Views but call the same action by using the interface. Don't use views that's strongly typed to interface if they need to show different properties. – Ufuk Hacıoğulları Jan 27 '11 at 14:57
0

There is no direct way of binding data to a interface/abstract class. The DefaultModelBinder will try to instantiate that type, which is (by definition) impossible.

So, IMHO, you should not use that option. And if you still want to share the same controller action between the two views, the usual way of doing that would be using a ViewModel.

Make your strongly-typed views reference that viewmodel. Make the single shared action receive an instance of it. Inside the action, you will decide which "real" model should be used...

If you need some parameter in order to distinguish where the post came from (view 1 or 2), just add that parameter to the ajax call URL.

Of course, another way is keeping what you have already tried (interface/abstract class), but you'll need a custom Model Binder in that case... Sounds like overcoding to me, but it's your choice.

Edit After my dear SO fellow @Charles Boyung made a gracious (and wrong) comment below, I've come to the conclusion that my answer was not exactly accurate. So I have fixed some of the terminology that I've used here - hope it is clearer now.

Community
  • 1
  • 1
rsenna
  • 11,775
  • 1
  • 54
  • 60
  • "There is no direct way of binding a view to a interface/abstract class." Really? Are you sure about that? Because I've created plenty of views where they are defined like this: <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> Sure looks like I'm binding to an interface there. – Charles Boyung Jan 26 '11 at 19:47
  • 1
    @Charles Boyung: Hm not quite. I'm talking about **binding**, which is, from the ASP.NET MVC standpoint, the mechanism for mapping HTTP request data directly into action method parameters and custom .NET objects. You are just pointing that views can **reference** an abstract model. So you are wrong (and even more of an arrogant prick)... :-D – rsenna Jan 26 '11 at 20:12
0

If you only need the RecordID, you can just have the controller method take int RecordID and it will pull that out of the form post data instead of building the view model back up and providing that to your action method.

[HttpPost]
public ActionResult ValidateRecordID(int RecordID) {
    // TODO: Do some verification code here

    return this.Json("Validated.");
}
NerdFury
  • 18,876
  • 5
  • 38
  • 41
  • This is they way I might have to end up going. I'm just wondering if there is a way to use the same Action on a controller with a different model for a strongly typed view... – Sean Jan 26 '11 at 22:28
  • I ended up using this method to solve my problem. But I would still like to see if the above can be done easily without overcoding. – Sean Jan 27 '11 at 00:26
  • This is what I ended up using, but isn't really the answer to the question. Thanks for the help though! – Sean Jan 27 '11 at 18:47
0

In the case above your action could accept two strings instead of a concrete type.

Another possibility is having two actions. Each action taking one of your types. I'm assuming that functionality each type is basically the same. Once the values have been extracted hand them off to a method. In your case method will probably be the same for each action.

public ActionResult Method1(Record record)
{
ProcessAction(record.id, record.Property);

}

public ActionResult Action2(OtherRecord record)
{

ProcessAction(record.id, record.OtherProperty);

}


private void ProcessAction(string id, string otherproperity)
{
//make happen
}
Chuck Conway
  • 16,287
  • 11
  • 58
  • 101
  • This is what I want to try and avoid though. Why have two different actions that do exactly the same thing? All I want to do is validate that a "field" has a certain mask too it. What if I have 20 different views that go to the same controller that require validation on the RecordID? Do I have 20 different actions? – Sean Jan 26 '11 at 22:27