Please help me on the following code. The Model class is using System.ComponentModel.DataAnnotation:
namespace Proj.Models
{
public class Customer
{
[Required]
public string CustomerID{get;set;}
[Required]
public string CustomerName{get;set;}
}
}
I have created a controller using this model, the action method being:
public class Customer:Controller
{
public ActionResult Details()
{
return View();
}
}
The razor view is Details.cshtml, having following markup and code:
#model Proj.Models.Customer
<form method="post">
#Html.EditorForModel()
<button>Submit!!</button>
</form>
However, when I click submit, no validation errors are seen as expected.
You need to create a method which takes your model as input like this:
[HttpPost]
public ActionResult Index(Customer customer)
{
return View();
}
The [HttpPost] ensures that the method is only called on POST requests.
You need to create editor template for your model. By default no validation messages will be emitted. Inside your editor template, you will have to use #ValidationMessageFor for your Required fields.
Hope this helps.
Related
I am unable to to get a custom form to display in Task Module. It's a form with few input elements and method="POST" attribute. When I remove "method" attribute the task module displays custom form correctly.
I just want to post input field values to controller.
PS: Everything works when I run those forms in browser. I have also added valid domains in teams and task module renders perfectly without method="POST" attribute in form tag.
This is my .cshtml page with form method.
Here is Controller class
public class HomeController : Controller
{
public SuspectRegistration registration;
public HomeController()
{
registration = new SuspectRegistration();
}
// GET: /<controller>/
public IActionResult Index()
{
return View();
}
public IActionResult CustomForm()
{
return View();
}
public IActionResult PRFPDetailsForm()
{
return View();
}
// This is the method where I need to get values, it works in browser without any issues.
[HttpPost]
public IActionResult PRFPDetailsForm(SuspectRegistration formData)
{
HttpContext.Session.SetString("formdata", JsonConvert.SerializeObject(formData));
return View("PRFPDetailsForm");
}
public IActionResult PRFPRegistrationConfirmation()
{
var value = HttpContext.Session.GetString("formdata");
var suspectRegistration = JsonConvert.DeserializeObject<SuspectRegistration>(value);
ViewBag.SuspectRegistration = suspectRegistration;
return View();
}
}
I missed to respond here. Your back end code has no issues. On frontend, you need to submit your frontend input values to "microsoftTeams.tasks.submitTask(youJSObject)" in js object and same thing you can receive in turnContext of the "OnTeamsTaskModulesSubmitAsync" method.
I am unable to make a simple MVC 3 controller/view/model program work with an ActionResult method that includes the Bind attribute with a Prefix property.
One example that I did try could populated the parameter when I call the action method from the URL.
Here is that example controller followed by its view:
//Controller
//public ActionResult PrefixExample(int number = 0)
public ActionResult PrefixExample([Bind(Prefix="okay")]int? number)
{
return View(number);
}
//View
#model Int32?
#{
ViewBag.Title = "Example";
}
<h2>Example</h2>
#using (Html.BeginForm())
{
if (#Model.HasValue)
{
<label>#Model.Value.ToString()</label>
} else {
<label>#Model.HasValue.ToString()</label>
}
<input type="submit" value="submit" />
}
If I use this url http://localhost/MVCApp/Home/Example?okay=3 the parameter, number, is populated. If I use this url http://localhost/MVCApp/Home/Example?number=3, the parameter isn't populated. Interestingly, with the first url, when I view source, the prefix okay doesn't show up.
If I uncomment the first line of my controller and comment out the second line, the opposite is true: the url with okay won't populate number but the second url using number will populate number in the controller.
I would like to know how to make the following example accept a url and correctly set the "view source" prefix. Here is a possible url http://localhost/MVCApp/Home/SpecificPerson?PersonId=0&FirstName=Joe&LastName=Doe
Note, that if I remove the Bind attribute from the controller method, the above url will work with the MVC app below.
Here is my model/controller/view:
//model:
namespace MVCApp.Models
{
public class Person
{
[HiddenInput(DisplayValue = false)]
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
//controller
namespace MVCApp.Controllers
{
public class HomeController : Controller
{
public ActionResult SpecificPerson([Bind(Prefix = "myPerson")]Person aPerson)
{
return View("SpecificPerson", aPerson);
}
}
}
//view
#model MVCApp.Models.Person
#{
ViewBag.Title = "SpecificPerson";
}
<h2>SpecificPerson</h2>
#Html.EditorForModel();
<br />
#Html.EditorFor(m => m);
I would like to see the above example work. Anyone who could show me why it doesn't work as I expect or what I can do to make it work this way would be greatly appreciated.
Thank you in advance.
I think the EditorForModel brought you a bit off track. If you check the html that is generated by this helper you will see that it's not wrapped in a form. Besides that I think the EditorForModel will not serve you as much as you would like to. You can also get it to work correctly without specifying the Bind prefix.
//model
public class Person
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
//controller
public class HomeController : Controller
{
public ActionResult Index(Person person)
{
if("POST".Equals(Request.HttpMethod))
{
//for example do some validation and redirect
}
return View(person);
}
}
//view
#model Application.Models.Person //only as example use own
#using(Html.BeginForm("Index","Home", FormMethod.POST))
{
#Html.HiddenFor(x=> x.Id)
<div>
#Html.LabelFor(x=> x.FirstName)
#Html.TextBoxFor(x=> x.FirstName)
</div>
<div>
#Html.LabelFor(x=> x.LastName)
#Html.TextBoxFor(x=> x.LastName)
</div>
<input type="submit" value="Do a post request"/>
}
Also if you use a url like /Home/Index?Id=9 and you look the HTML code you will see that there will be a element with input type=hidden and the value of 9. You could also use two actionresults to split your logic with [HttpGet] and [HttpPost] as attribute of your Action.
And as last I recommend you to check out the newer versions of MVC; MVC 5 is already out...
I am making WCF service call using MyViewRequest view fields inside HttpPost ActionHandler. The goal is to show response using partial view, MyViewResponse
In brief I need to achieve these two items-
Disable load of partial view on first load.
Display Response (along with Request) after service call.
MyViewRequest.cshtml
#using (Html.BeginForm())
{
#Html.ValidationSummary(false)
//html code
}
</div>
<div id="dvResponse">
#Html.Partial("MyViewResponse");
</div>
Partial view: MyViewResponse.cshtml
#model MvcApplication3.Models.MyModel
#{
ViewBag.Title = "MyViewResponse";
}
<h2>MyView</h2>
#Html.Label(Model.MyName, "My Name")
This was pretty straight forward in Asp.Net using userControl, But stuck up here, How can we achieve this in MVC3.
I think the best way is to transfer your data using ViewModels. Let's assume you want to have an app something like stackoverflow where you have a question and user can post an answer and it will be shown after the post along with the question.
public class PostViewModel
{
public int ID { set;get;}
public string Text { set;get;}
public List<PostViewModel> Answers { set;get;}
public string NewAnswer { set;get;}
}
in your GET action, you show the question. Get the id from the url and get the Question details from your service/repositary.
public ActionResult Show(int id)
{
var post=new PostViewModel();
post=yourService.GetQuestionFromID(id);
post.Answers=yourService.GetAnswersFromQuestionID(id);
return View(post);
}
Assuming yourService.GetQuestionFromID method returns an object of PostViewModel with the propety values filled. The data can be fetched from your database or via a WCF service call. It is up to you. Also yourService.GetAnswersFromQuestionID method returns a list of PostViewModel to represent the Answers for that question. You may put both these into a single method called GetQuestionWithAnswers. I wrote 2 methods to make it more clear.
Now in your Show view
#model PostViewModel
#Html.LabelFor(x=>x.Text);
#using(Html.Beginform())
{
#Html.HiddenFor(x=>x.ID);
#Html.TextBoxFor(x=>x.NewAnswer)
<input type="submit" />
}
<h3>Answers</h3>
#if(Model.Answers!=null)
{
#Html.Partial("Responses",Model.Answers)
}
And your Partial view will be strongly typed to a collection of PostViewModel
#model List<PostViewModel>
#foreach(var item in Model)
{
<div> #item.Text </div>
}
Handling the postback is simple (HttpPost)
[HttpPost]
public ActionResult Show(PostViewModel model)
{
if(ModelState.IsValid)
{
//get your data from model.NewAnswer property and save to your data base
//or call WCF method to save it.
//After saving, Let's redirect to the GET action (PRG pattern)
return RedirectToAction("Show",new { #id=model.ID});
}
}
i looked at : http://weblogs.asp.net/shijuvarghese/archive/2010/03/06/persisting-model-state-in-asp-net-mvc-using-html-serialize.aspx
but when i post the page the model(ie person) returns as null?
[HttpPost]
public ActionResult Edit([DeserializeAttribute]Person person, FormCollection formCollection)
{
//this line has an error:
TryUpdateModel(person, formCollection.ToValueProvider());
return View(person);
}
<% using (Html.BeginForm("Edit", "Home"))
{%>
<%=Html.Serialize("person", Model)%>
<%=Html.EditorForModel() %>
<button type="submit">
go</button>
<%
}%>
[Serializable]
public class Person
{
public string name { get; set; }
public string suburb { get; set; }
}
Why you are trying to bind the person from the request using the following:
TryUpdateModel(person, formCollection.ToValueProvider());
when you explicitly know that there is no such thing in the request? This line invokes the model binder and tries to read it from the request values. But in your form you only have a single hidden field. So your action should look like this:
[HttpPost]
public ActionResult Edit([DeserializeAttribute]Person person)
{
// Do something with the person object that's passed as
// action argument
return View(person);
}
Also your scenario looks strange. You have a view which seems to be strongly typed to this Person object in which you are using Html.EditorForModel meaning that you are offering the user possibility to edit those values. If you serialize the model you will get old values in your controller action. This attribute is only useful when you want to persist some model between multiple requests but there is no corresponding input fields in the form so that the default model binder can reconstruct the instance in the POST actions.
At the end of my view, I call this:
<%= Html.Action("ProductLayoutAndLimits", this.Model) /* Render product-specific options*/ %>
That action is virtual in my controller:
[ChildActionOnly]
public virtual ActionResult ProductLayoutAndLimits(DeliveryOptionsViewModel optionsViewModel)
{
return new EmptyResult();
}
The intent was that I would override this method in a product specific controller. So naturally, I did this:
public override System.Web.Mvc.ActionResult ProductLayoutAndLimits(DeliveryOptionsViewModel optionsViewModel)
{
But the breakpoint isn't hitting, so my override is not getting picked up. Is there a different overload I should be using? Or do I need to pass in a different object? Or is there an annotation that I need on my product specific action in order for it to be detected?
Any help is appreciated. Thanks!
Edit
While all suggestions are appreciated, I am most interested in solutions that actually answer my question, rather than suggesting a different technique.
Templates have been suggested, but please note that I need controller code to be executed before any new additional view code is rendered. The base controller is in a solution that serves as a platform to other products. They cannot do anything product specific. After they render their view, the intent is that my override of the child action will be called. My controller code will check a number of things in order to determine how to set properties on my model before it renders the view.
Edit
I found the problem. I feel silly, as usual. Html.Action was being called from Platform's view code. It turned out that we have been using a product specific view for this since July. I didn't notice because we don't typically use product specific views. Whoops!
Why are you using child actions and overriding controllers to handle this? Why not display templates:
<%= Html.DisplayForModel("ProductLayoutAndLimits") %>
where ProductLayoutAndLimits would be the name of the corresponding display template.
Example:
Model:
public class BaseViewModel
{
public string BaseProp { get; set; }
}
public class DerviedViewModel : BaseViewModel
{
public string DerivedProp { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new DerviedViewModel
{
BaseProp = "base prop",
DerivedProp = "derived prop"
});
}
}
View (~/Views/Home/Index.cshtml):
#model AppName.Models.BaseViewModel
#Html.DisplayForModel()
Display Template (~/Views/Home/DisplayTemplates/DerviedViewModel.cshtml):
#model AppName.Models.DerviedViewModel
#Html.DisplayFor(x => x.BaseProp)
#Html.DisplayFor(x => x.DerivedProp)
Of course you could also have a display template for the base class (~/Views/Home/DisplayTemplates/BaseViewModel.cshtml):
#model AppName.Models.BaseViewModel
#Html.DisplayFor(x => x.BaseProp)
and this template would have been rendered if your controller action had returned the base class as model.