views:

212

answers:

1

I need to create something similar to how MVC invokes an Method(Action) and also uses the Model Binder to map a NamedValueCollection to the parameters on that method. Basically I have a Controller action that needs to dynamically call a method on a class, the controller has any information sent in a form or query string plus the name of the method to invoke as a string.

As far as I am concerned it's the same as invoking an action. I am essentially passing it down another level (there is a good reason I can't have these methods on the controller btw).

I downloaded the ASP.Net MVC 1.0 Source but there are a bunch of classes, I am having trouble finding the code that handles this.

I know how to invoke an method whose name is contained in a string, but maybe there is a better way that MVC uses. I also need to know how to use the Model Binders to make Request.Form + Query Strings to that methods parameters.

If anyone could point me to either the code in the MVC source that does this or point me in the right direction with regards to using the default Model Binder in MVC manually I would be grateful.

Let me know if I can make this clearer.

Thanks

+3  A: 

It's complicated. FindAction is called on ControllerActionInvoker. This calls, eventually, ReflectedControllerDescriptor.FindAction, which in turn calls ActionMethodSelector.FindActionMethod, which calls RunSelectionFilters on the same type. That method takes a list of methods passed him by the collar, and iterates them, examining the arguments on each method and comparing them with the values in the request. Because this has to run quickly on a request comes in, this is all cached, and because it is designed to be extensible, there are some abstract types in between the layers I've described. Hence, it can be a little difficult to follow at first, and it would probably be difficult to repurpose it for non-controller logic. However, you could use it as a model for implementing your own system. I think it's a little too complicated for a domain-specific application. The number of extension points is probably appropriate for the MVC framework, but for your own code, YAGNI.

I hope this gives you enough to get started, however.

Regarding using a model binder without the web stack: Well, you still need MVC, but not necessarily a web server. Here's how we do it in a unit test:

    internal static T Bind<T>(string prefix, FormCollection collection, ModelStateDictionary modelState) where T:BaseTimeRecordPresentationModel
    {
        var mbc = new ModelBindingContext()
        {
            ModelName = prefix,
            ModelState = modelState,
            ModelType = typeof(T),
            ValueProvider = collection.ToValueProvider()
        };
        IModelBinder binder = new TimeRecordModelBinder();
        var cc = new ControllerContext();

        return binder.BindModel(cc, mbc) as T;
    }

    internal static T BindAndAssertValid<T>(string prefix, FormCollection collection) where T:BaseTimeRecordPresentationModel
    {
        var msd = new ModelStateDictionary();
        var result = Bind<T>(prefix, collection, msd);
        if (!msd.IsValid)
        {
            Assert.Fail(ModelStateValidationSummary(msd));
        }
        return result;
    }
Craig Stuntz
Yes. I found FindAction and began to see it won't be easy to port. I have written the part that finds the correct method, easy, but do you know if it's possible to use the Model Binders manually?
Damien
See updated answer.
Craig Stuntz