views:

197

answers:

2

If i have a Controller Action that may recieve both HTTP GET and HTTP POST from a number of different sources with each source sending different data e.g.

  1. Source1 performs a form POST with two form items Item1 and Item2
  2. Source2 performs a GET where the data is contained in the query string (?ItemX=2&ItemY=3)

Is it possible to have a controller action that will cater for all these cases and perform binding automatically e.g. public ActionResult Test(Dictionary data) { // Do work ... return View(); }

Is this possible with a custom binder or some other way? Dont want to work directly with HttpContext.Request if possible

+1  A: 

The usual pattern is to have two controller methods One controller method handles the GET, the other controller method handles the POST:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MyControllerMethod(string itemX, string itemY)
{
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyControllerMethod(MyViewDataObject data)
{
}

If you need help binding lists, collections or dictionaries you can find it here.

Robert Harvey
++ The idea is that displaying a page and handling input are very distinct actions and shouldn't be combined.
BC
Robert thanks for replyI may not have been clear in my question.I want the ability to have one controller action recieve both the HTTP GETS and POSTS as these will come from 3rd parties.Also these third parties will send totally different data so I cannot do strongly typed binding to an object as you suggest(MyViewDataObject). This is why I asked is it possible to bind to a dictionary. Do you know if this is possible?
Noel
I can't think of *any* scenario where you would be forced to handle the GET and POST in the same method. There is a link in my answer that shows how to bind lists, but if you are going to accept a plain ole object in the controller method, you're probably going to have to bind it yourself; the MVC data binders won't do it for you automatically unless you can strongly type it.
Robert Harvey
We are not forced to handle the GET and POST in the same action methodHowever as we want to handle all requests in the one place(action method) for all third parties that call into use weather they POST or GET with different data.
Noel
Well, the Url will have the same routing for both GET and POST, and will therefore look the same to the outside user in both cases (except for the Url parameters), so the two controller methods are essentially invisible to third parties. Given this transparency, I don't see any compelling reason to shoehorn the GET and POST activity into the same controller method, especially since the MVC framework gives you the ability to gracefully separate the two operations. Not trying to argue with you, but combining the two into a single method is unnecessary.
Robert Harvey
Robert thanks for reply. Looking into a solution and will post when working
Noel
A: 

This solution works, not best for unit testing

     public object BindModel(
                    ControllerContext controllerContext, 
                    ModelBindingContext bindingContext)
                {  
                    TestIBE.Models.IBERequest _IBERequest;
                    HttpContextBase _httpContext;
                    Dictionary<string, string> _requestData;


                    _httpContext = controllerContext.HttpContext;
                    _requestData = this.CreateRequestData(_httpContext.Request);

                    _IBERequest = new TestIBE.Models.IBERequest(
                        _httpContext.Session.SessionID,
                        _httpContext.Request.UserHostAddress,
                        _httpContext.Request.UserAgent,
                        _httpContext.Request.Url,
                        _requestData);

                    return _IBERequest;
                }


                private Dictionary<string, string> CreateRequestData(
                    HttpRequestBase subject)
                {
                    Dictionary<string, string> _result;


                    _result = new Dictionary<string, string>();
                    subject.Form.AllKeys.ForEach(key => _result.Add(key, subject.Form[key]));
                    subject.QueryString.AllKeys.ForEach(key => { if (!_result.ContainsKey(key)) { _result.Add(key, subject.QueryString[key]); } });

                    return _result;
                }


public class IBEController : Controller
    {
        public ActionResult Landing(
            [ModelBinder(typeof(TestIBE.Helpers.Binders.IBEModelBinder))] TestIBE.Models.IBERequest IBERequest)
        {
            // TODO
            return View();
        }
    }
Noel