Asp.Net mvc nested actions HTTPPOST - asp.net-mvc

i ve got a weird problem. My view :
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using(Html.BeginForm())
{
<input type="submit" value="asds"/>
}
#Html.Action("Index2")
My Controller:
public class DefaultController : Controller
{
//
// GET: /Default1/
[HttpPost]
public ActionResult Index(string t)
{
return View();
}
public ActionResult Index()
{
return View();
}
//
// GET: /Default1/
[HttpPost]
public ActionResult Index2(string t)
{
return PartialView("Index");
}
[ChildActionOnly()]
public ActionResult Index2()
{
return PartialView();
}
}
When i click on a button [HttpPost]Index(string t) is executed, wich is fine. But after that [HttpPost]Index2(string t) is excuted and thats really weird to me because i ve posted data for Index action not for Index2. My logic tells me that [ChildActionOnly()]ActionResult Index2() instead of HttpPost one.
Why is this happening? How can override this behaviour without renaming [HttpPost]Index2 action?

That's the default behavior. It is by design. If you cannot change the POST Index2 action name you could write a custom action name selector that will force the usage of the GET Index2 action even if the current request is a POST request:
public class PreferGetChildActionForPostAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if (string.Equals("post", controllerContext.HttpContext.Request.RequestType, StringComparison.OrdinalIgnoreCase))
{
if (methodInfo.CustomAttributes.Where(x => x.AttributeType == typeof(HttpPostAttribute)).Any())
{
return false;
}
}
return controllerContext.IsChildAction;
}
}
and then decorate your two actions with it:
[HttpPost]
[PreferGetChildActionForPost]
public ActionResult Index2(string t)
{
return PartialView("Index");
}
[ChildActionOnly]
[PreferGetChildActionForPost]
public ActionResult Index2()
{
return PartialView();
}

Related

Model Binding Object properties gets NULL on passing while Redirecting to another Action Method [duplicate]

I want to know, there is any technique so we can pass Model as a parameter in RedirectToAction
For Example:
public class Student{
public int Id{get;set;}
public string Name{get;set;}
}
Controller
public class StudentController : Controller
{
public ActionResult FillStudent()
{
return View();
}
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return RedirectToAction("GetStudent","Student",new{student=student1});
}
public ActionResult GetStudent(Student student)
{
return View();
}
}
My Question - Can I pass student model in RedirectToAction?
Using TempData
Represents a set of data that persists only from one request to the
next
[HttpPost]
public ActionResult FillStudent(Student student1)
{
TempData["student"]= new Student();
return RedirectToAction("GetStudent","Student");
}
[HttpGet]
public ActionResult GetStudent(Student passedStd)
{
Student std=(Student)TempData["student"];
return View();
}
Alternative way
Pass the data using Query string
return RedirectToAction("GetStudent","Student", new {Name="John", Class="clsz"});
This will generate a GET Request like Student/GetStudent?Name=John & Class=clsz
Ensure the method you want to redirect to is decorated with [HttpGet] as
the above RedirectToAction will issue GET Request with http status
code 302 Found (common way of performing url redirect)
Just call the action no need for redirect to action or the new keyword for model.
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return GetStudent(student1); //this will also work
}
public ActionResult GetStudent(Student student)
{
return View(student);
}
Yes you can pass the model that you have shown using
return RedirectToAction("GetStudent", "Student", student1 );
assuming student1 is an instance of Student
which will generate the following url (assuming your using the default routes and the value of student1 are ID=4 and Name="Amit")
.../Student/GetStudent/4?Name=Amit
Internally the RedirectToAction() method builds a RouteValueDictionary by using the .ToString() value of each property in the model. However, binding will only work if all the properties in the model are simple properties and it fails if any properties are complex objects or collections because the method does not use recursion. If for example, Student contained a property List<string> Subjects, then that property would result in a query string value of
....&Subjects=System.Collections.Generic.List'1[System.String]
and binding would fail and that property would be null
[HttpPost]
public async Task<ActionResult> Capture(string imageData)
{
if (imageData.Length > 0)
{
var imageBytes = Convert.FromBase64String(imageData);
using (var stream = new MemoryStream(imageBytes))
{
var result = (JsonResult)await IdentifyFace(stream);
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(serializer.Serialize(result.Data));
if (faceRecon.Success) return RedirectToAction("Index", "Auth", new { param = serializer.Serialize(result.Data) });
}
}
return Json(new { success = false, responseText = "Der opstod en fejl - Intet billede, manglede data." }, JsonRequestBehavior.AllowGet);
}
// GET: Auth
[HttpGet]
public ActionResult Index(string param)
{
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(param);
return View(faceRecon);
}
[NonAction]
private ActionResult CRUD(someModel entity)
{
try
{
//you business logic here
return View(entity);
}
catch (Exception exp)
{
ModelState.AddModelError("", exp.InnerException.Message);
Response.StatusCode = 350;
return someerrohandilingactionresult(entity, actionType);
}
//Retrun appropriate message or redirect to proper action
return RedirectToAction("Index");
}
i did find something like this, helps get rid of hardcoded tempdata tags
public class AccountController : Controller
{
[HttpGet]
public ActionResult Index(IndexPresentationModel model)
{
return View(model);
}
[HttpPost]
public ActionResult Save(SaveUpdateModel model)
{
// save the information
var presentationModel = new IndexPresentationModel();
presentationModel.Message = model.Message;
return this.RedirectToAction(c => c.Index(presentationModel));
}
}

Can we pass model as a parameter in RedirectToAction?

I want to know, there is any technique so we can pass Model as a parameter in RedirectToAction
For Example:
public class Student{
public int Id{get;set;}
public string Name{get;set;}
}
Controller
public class StudentController : Controller
{
public ActionResult FillStudent()
{
return View();
}
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return RedirectToAction("GetStudent","Student",new{student=student1});
}
public ActionResult GetStudent(Student student)
{
return View();
}
}
My Question - Can I pass student model in RedirectToAction?
Using TempData
Represents a set of data that persists only from one request to the
next
[HttpPost]
public ActionResult FillStudent(Student student1)
{
TempData["student"]= new Student();
return RedirectToAction("GetStudent","Student");
}
[HttpGet]
public ActionResult GetStudent(Student passedStd)
{
Student std=(Student)TempData["student"];
return View();
}
Alternative way
Pass the data using Query string
return RedirectToAction("GetStudent","Student", new {Name="John", Class="clsz"});
This will generate a GET Request like Student/GetStudent?Name=John & Class=clsz
Ensure the method you want to redirect to is decorated with [HttpGet] as
the above RedirectToAction will issue GET Request with http status
code 302 Found (common way of performing url redirect)
Just call the action no need for redirect to action or the new keyword for model.
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return GetStudent(student1); //this will also work
}
public ActionResult GetStudent(Student student)
{
return View(student);
}
Yes you can pass the model that you have shown using
return RedirectToAction("GetStudent", "Student", student1 );
assuming student1 is an instance of Student
which will generate the following url (assuming your using the default routes and the value of student1 are ID=4 and Name="Amit")
.../Student/GetStudent/4?Name=Amit
Internally the RedirectToAction() method builds a RouteValueDictionary by using the .ToString() value of each property in the model. However, binding will only work if all the properties in the model are simple properties and it fails if any properties are complex objects or collections because the method does not use recursion. If for example, Student contained a property List<string> Subjects, then that property would result in a query string value of
....&Subjects=System.Collections.Generic.List'1[System.String]
and binding would fail and that property would be null
[HttpPost]
public async Task<ActionResult> Capture(string imageData)
{
if (imageData.Length > 0)
{
var imageBytes = Convert.FromBase64String(imageData);
using (var stream = new MemoryStream(imageBytes))
{
var result = (JsonResult)await IdentifyFace(stream);
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(serializer.Serialize(result.Data));
if (faceRecon.Success) return RedirectToAction("Index", "Auth", new { param = serializer.Serialize(result.Data) });
}
}
return Json(new { success = false, responseText = "Der opstod en fejl - Intet billede, manglede data." }, JsonRequestBehavior.AllowGet);
}
// GET: Auth
[HttpGet]
public ActionResult Index(string param)
{
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(param);
return View(faceRecon);
}
[NonAction]
private ActionResult CRUD(someModel entity)
{
try
{
//you business logic here
return View(entity);
}
catch (Exception exp)
{
ModelState.AddModelError("", exp.InnerException.Message);
Response.StatusCode = 350;
return someerrohandilingactionresult(entity, actionType);
}
//Retrun appropriate message or redirect to proper action
return RedirectToAction("Index");
}
i did find something like this, helps get rid of hardcoded tempdata tags
public class AccountController : Controller
{
[HttpGet]
public ActionResult Index(IndexPresentationModel model)
{
return View(model);
}
[HttpPost]
public ActionResult Save(SaveUpdateModel model)
{
// save the information
var presentationModel = new IndexPresentationModel();
presentationModel.Message = model.Message;
return this.RedirectToAction(c => c.Index(presentationModel));
}
}

Binding in ASP.NET MVC

My question is about binding in MVC. Could you please help me with it?
My controller:
public class TestController : Controller
{
//
// GET: /Test/
[HttpGet]
public ActionResult Index()
{
return View(new TestModel());
}
public ActionResult Index(TestModel test)
{
return View(test);
}
}
My View:
#model MvcApplication1.Models.TestModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.test) // or x.Test
<input type="submit" value="Set"/>
}
My model:
public class TestModel
{
public string test { get; set; } // or Test{get;set;}
}
The problem is connected with the name of parameter "test" in controller as I understand. I have just changed it to "model" and the binding is working. But it is not working in original state (the name of parameter is 'test'), 'test' parameter is null.
Please give me understand why the binding is not working in current example. Thank you a lot!
You need an [HttpPost] attribute on your second method. You also cannot use test as your variable name, as it is the same name as the property of the class you're attempting to bind to; the ModelBinder fails to determine which to use. Your code would look as follows:
public class TestController : Controller
{
//
// GET: /Test/
[HttpGet]
public ActionResult Index()
{
return View(new TestModel());
}
//
// POST: /Test/
[HttpPost]
public ActionResult Index(TestModel testModel)
{
return View(testModel);
}
}

Redirect from a [HttpGet] Action To [HttpPost] Action - MVC3

I want to redirect to a [HttpPost] Action from a [HttpGet] Action in the same controller.
Is it possible?
I'm trying to not rewrite the same code for a Login, because it is a complex, and not typical logon function
This is my code:
[HttpGet]
public ActionResult Login(){
return View();
}
[HttpPost]
public ActionResult Login(LoginModel model)
{
//search user and create sesion
//...
if (registered)
{
return this.RedirectToAction("Home","Index");
}else{
return this.RedirectToAction("Home", "signIn");
}
}
[HttpGet]
public ActionResult signIn(){
return View();
}
[HttpGet]
public ActionResult signInUserModel model)
{
//Register new User
//...
if (allOk)
{
LoginModel loginModel = new LoginModel();
loginModel.User = model.User;
loginModel.password = model.password;
//next line doesn't work!!!!!
return this.RedirectToAction("Home","Login", new { model = loginModel);
}else{
//error
//...
}
}
Any help would be appreciated.
Thanks
You can return a different View from the method name
public ActionResult signInUserModel model)
{
...
return View("Login", loginModel);
}
Bit late, but I just had the same issue...
You could refactor the core login logic out from the Post method and then call that new method from both places.
e.g. Suppose you create a LoginService class to handle logging someone in. It's just a case of using that from both your actions, so no need to redirect from one action to the other
It is possible. All actions must be in the same controller.
public ActionResult Login(){
return View();
}
[HttpPost]
public ActionResult Login(LoginModel model)
{
//search user and create sesion
//...
if (registered)
{
return RedirectToAction("Index");
}
return View(model);
}
public ActionResult SignIn(){
return View();
}
[HttpPost]
public ActionResult SignIn(UserModel model)
{
//Register new User
//...
if (allOk)
{
return RedirectToAction("Login");
}
return View(model);
}

Redirect to same view

I am working on a ASP.NET MVC website and I am new to this.
I have a controller with few actions. I want to use these actions through out my website.
For example
[HttpPost]
public ActionResult MyAction(ViewModel model)
{
if (ModelState.IsValid)
{
//code is here
}
return RedirectToAction(); // redirect to same view
}
I want to redirect to same view from where request is generated. I am not sure if this is possible or not ?
Based on your comment, I would create a Controller that looks like:
public MyController : Controller
{
private ActionResult SharedMethod(SomeModel model)
{
if (ModelState.IsValid)
{
//code is here
}
// viewname is required, otherwise the view name used will be
// the original calling method (ie public1.cshtml, public2.cshtml)
return this.View("SharedViewName");
}
public ActionResult Public1(SomeModel model)
{
return this.SharedMethod(model);
}
public ActionResult Public1(SomeModel model)
{
return this.SharedMethod(model);
}
}

Resources