I have a page that has 2 text boxes First Name and last Name after user click on sign up button API will run and returns user info and shows another page(view) that had user Phone, email,.. That fill with the info that API returns. I have 1 controller and 2 views.
I get the info from API and return the second view but not sure how fill the text boxes with the info I have. The problem is using the models in view, I have 2 models one for each view. I am getting this error when I call the second view:
The model item passed into the dictionary is of type 'System.Collections.Generic.Dictionary`2[System.String,System.Object]', but this dictionary requires a model item of type Models.CreateLogInRequest'.
This is my controller:
[HttpGet]
public ActionResult SearchUser()
{
return View();
}
[HttpPost]
public async Task<ActionResult> SearchUser(UserSearchRequest userSearchRequest)
{
HttpClient client = new HttpClient();
object userObject = null;
string baseUrl = "http://test/api/users";
if (userSearchRequest.FirstName != null && userSearchRequest.LastName)
{
var response = await client.GetAsync(string.Format("{0}{1}/{2}/{3}", baseUrl, "/users", userSearchRequest.FirstName, userSearchRequest.LastName));
if (response.IsSuccessStatusCode)
{
userObject = new JavaScriptSerializer().DeserializeObject(response.Content.ReadAsStringAsync().Result) as object;
}
}
if (userObject != null)
{
return View("Create", userObject);
}
return View("Create", null);
}
[HttpPost]
public ActionResult Create(CreateLogInRequest createLogInRequest)
{
return View();
}
This is my First View that shows 2 text boxes:
#using (Html.BeginForm("SearchUser", "SignUp", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input id="FirstName" name="FirstName" type="text" placeholder="First NAME" />
<input id="LastName" name="LastName" type="text" placeholder="LastName " />
<input id="btnSubmit" name="btnSubmit" type="submit" value="SIGN UP TODAY" />
}
and this is my model for 1st view:
public class UserSearchRequest
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
This is the second View:
#model Models.CreateLogInRequest
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm("create", "SignUp", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input id="Email" name="Email" type="text" placeholder="Email" value="#Model.Email" />
<input id="Phone" name="Phone" type="text" placeholder="Phone" value="#Model.Phone" />
<input id="btnSubmit" name="btnSubmit" type="submit" value="CREATE ACCOUNT" />
}
and this is Model for this view:
public class CreateLogInRequest
{
public string Email { get; set; }
public string Phone { get; set; }
....
}
See my comments and try this:
[HttpGet]
public ActionResult SearchUser()
{
return View();
}
[HttpPost]
public async Task<ActionResult> SearchUser(UserSearchRequest userSearchRequest)
{
HttpClient client = new HttpClient();
CreateLogInRequest userObject = null;
string baseUrl = "http://test/api/users";
if (userSearchRequest.FirstName != null && userSearchRequest.LastName)
{
var response = await client.GetAsync(string.Format("{0}{1}/{2}/{3}", baseUrl, "/users", userSearchRequest.FirstName, userSearchRequest.LastName));
if (response.IsSuccessStatusCode)
{
userObject = new JavaScriptSerializer().DeserializeObject<CreateLogInRequest>(response.Content.ReadAsStringAsync().Result);
}
}
if (userObject != null)
{
return RedirectToAction("Create", userObject);
}
return View("Create", null);
}
[HttpPost]
public ActionResult Create(CreateLogInRequest createLogInRequest)
{
return View();
}
In the Controller you can create a new instance of Models.CreateLogInRequest model and fill the related properties received from 1st View. If Models.CreateLogInRequest does not contain such properties then it is better to load these values by using TempData or ViewBag in the Controller retrieved from the 1st View and pass them to the 2nd View. For the differences between ViewBag, ViewData, or TempData you might have a look at When to use ViewBag, ViewData, or TempData in ASP.NET MVC 3 applications. Hope this helps...
Related
if I call the POST action method I want to get the data from the files-object of my GET action method.
public class UploadController:Controller {
public IActionResult Index(){
// Here is some code
return View(files);
}
[HttpPost]
public IActionResult Index(IFormFile importFile){
{
// Here I want to work with data from the files object of my Index() method above
return View("Index", newFiles);
}
}
My View looks like this:
#using MVC-project.Models
#model UploadViewModel
<table>
<tr>
<th>File Name</th>
<th></th>
</tr>
#foreach (string file in Model.FileName )
{
<tr>
<td>#file</td>
<td>#Html.ActionLink("Download", "DownloadFile", new { fileName = file })</td>
</tr>
}
</table>
#using (Html.BeginForm("Index", "Upload", FormMethod.Post, new { #id = "upldFrm", #enctype = "multipart/form-data" }))
{
<div class="row">
<div class="form-group col-md-6">
<input type="file" class=" form-control" name="importFile" />
</div>
<div class="form-group col-md-6">
<input type="submit" name="filesubmit" value="Upload" />
</div>
</div>
}
// Here is some code and if-case for processing after the POST submit
How can I use the data from the files object of my GET Index() action method in my POST Index method?
There are a number of ways to do this. You could put the files in a view data dictionary in the get controller.
ViewData["Files"] = files
Then retrieve it from your post.
var files = ViewData["Files"]
You could also pass the files to a view model in your get controller, send it to your view. Then pass it to the post action when you submit the form on the view.
public class ViewModel {
public string Files {get; set;}
public IFormFile File {get; set;}
}
[HttpGet]
public IActionResult Index(){
var viewModel = new ViewModel
{
Files = files
};
return View(viewModel);
}
[HttpPost]
public IActionResult Index(ViewModel viewModel){
....
}
Here is the example to get the data before the post action.
public ActionResult Edit(int id)
{
HttpResponseMessage response =GlobalVariables.webApiClient.GetAsync("Tbl_Books/"+ id.ToString()).Result;
return View(response.Content.ReadAsAsync<Books>().Result);
}
[HttpPost]
public ActionResult Edit(Books newbook)
{
HttpResponseMessage response =GlobalVariables.webApiClient.PostAsJsonAsync("Tbl_Books", newbook).Result;
HttpResponseMessage response =
GlobalVariables.webApiClient.PutAsJsonAsync("Tbl_Books/" + newbook.BookId, newbook).Result;
return RedirectToAction("Index");
}
Here I will get the data from my get API method and this data is passed to the post view[HttpPost] and then post or put action can be performed.
I'm working on Asp.net project. I created a Form, which asks for connectionId and holderFirstName as Input. The name of asp-action is SendProofNameRequest.
In Controller, I wrote a Method SendProofNameRequest which take connectionId and holderFirstName as Parameters. But the problem is, the purpose I'm taking holderFirstName as Input is to use this in another Method (VerifyFirstName).
So, my question is how to take holderFirstName as input from user and use this in another method / VerifyFirstName (not SendProofNameRequest).
Details.cshtml
<form class="input-group mb-3" asp-controller="Proof" asp-action="SendProofNameRequest">
<input type="hidden" name="connectionId" value="#Model.Connection.Id" />
<input type="text" name="holderFirstName" autocomplete="off" class="form-control" placeholder="Enter First Name" aria-label="First Name" aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-outline-info" type="submit">Request a Proof of First Name</button>
</div>
</form>
ProofController.cs
[HttpPost]
public async Task<IActionResult> SendProofNameRequest(string connectionId, out string holderFirstName)
{
var agentContext = await _agentProvider.GetContextAsync();
var connectionRecord = await _walletRecordService.GetAsync<ConnectionRecord>(agentContext.Wallet, connectionId);
var proofNameRequest = await CreateProofNameMessage(connectionRecord);
await _messageService.SendAsync(agentContext.Wallet, proofNameRequest, connectionRecord);
return RedirectToAction("Index");
}
VerifyFirstName Method
I want to replace firstname (static value) with holderFirstName (dynamic value / user entered in form)
public bool VerifyFirstName(PartialProof proof)
{
var firstName = "Fyodor";
var name = proof.RequestedProof.RevealedAttributes.First();
if (name.Value.Raw.Equals(firstName))
{
return true;
}
return false;
}
UPDATE
As u said to add models, I did that... add the models in ViewModel page and call the #model in View page..
Now, to call the stored values in model in Verify methods controller.
VerifyProof(string proofRecordId) methods calls for another method VerifyFirstName(proof) which does the actual verification.
Kindly have a look at code and can u point out where to add model.HolderFirstName and SendNameRequestViewModel model in which method e.g. VerifyProof(string proofRecordId), VerifyFirstName(proof).. I was getting an errors..
[HttpGet]
public async Task<IActionResult> VerifyProof(string proofRecordId, SendNameRequestViewModel model)
{
var agentContext = await _agentProvider.GetContextAsync();
var proofRecord = await _proofService.GetAsync(agentContext, proofRecordId);
var request = JsonConvert.DeserializeObject<ProofRequest>(proofRecord.RequestJson);
var proof = JsonConvert.DeserializeObject<PartialProof>(proofRecord.ProofJson);
bool verified = false;
switch (request.Name)
{
case "ProveYourFirstName":
verified = VerifyFirstName(proof, model.HolderFirstName); break;
default:
break;
}
if (!verified)
{
proofRecord.State = ProofState.Rejected;
await _walletRecordService.UpdateAsync(agentContext.Wallet, proofRecord);
}
return RedirectToAction("Index");
}
public bool VerifyFirstName(PartialProof proof, SendNameRequestViewModel model.HolderFirstName)
{
var firstName = model.HolderFirstName;
var name = proof.RequestedProof.RevealedAttributes.First();
if (name.Value.Raw.Equals(firstName))
{
return true;
}
return false;
}
First of all, the actions/methods in the controller class are meant to handle requests coming from the client to the server. They're not just methods in a class.
Hence I think you need to take out out keyword from the parameter holderFirstName. Or better, to use a view model to pass between the view and the controller:
public class SendNameRequestViewModel
{
[Required]
public string ConnectionId { get; set; }
[Required]
public string HolderFirstName { get; set; }
}
public class ProofController : Controller
{
public async Task<IActionResult> SendNameRequest(string connectionId)
{
// Initialize the view model if needed, i.e., filling its ConnectionId either
// from query string or cache. I don't know how you get the connectionId
var agentContext = await _agentProvider.GetContextAsync();
var connectionRecord = await _walletRecordService.GetAsync<ConnectionRecord>(agentContext.Wallet, connectionId);
if (connectionRecord == null)
{
return NotFound();
}
var vm = new SendNameRequestViewModel
{
ConnectionId = connectionId
};
return View(vm);
}
}
Then on the view, you declare its model as SendNameRequestViewModel so that you don't have to hard code the input names/
Notes: I've also added validation summary and validation message for inputs.
#model SendNameRequestViewModel
...
<form class="input-group mb-3" method="post" asp-controller="Proof" asp-action="SendNameRequest">
<input type="hidden" asp-for="ConnectionId" />
<div asp-validation-summary="ModelOnly"></div>
<input asp-for="HolderFirstName" autocomplete="off" class="form-control"
placeholder="Enter First Name" aria-label="First Name" aria-describedby="basic-addon2">
<span asp-validation-for="HolderFirstName" class="text-danger"></span>
<div class="input-group-append">
<button class="btn btn-outline-info" type="submit">Request a Proof of First Name</button>
</div>
</form>
For your VerifyFirstName check, there are so many way to do it. You can directly run its logic in the controller action body, for example. I would create an extension method against PartialProof object:
public static class PartialProofExtensions
{
public static bool VerifyFirstName(this PartialProof proof, string firstName)
{
if (proof == null)
{
return false;
}
var name = proof.RequestedProof.RevealedAttributes
.FirstOrDefault();
return (name != null && name.Value.Raw.Equals(firstName));
}
}
When the form is posting back, you can just run the validation check in the action method:
[HttpPost]
[ValidateAntiforgeryToken]
public async Task<IActionResult> SendNameRequest(SendNameRequestViewModel model)
{
if (ModelState.IsValid)
{
var agentContext = await _agentProvider.GetContextAsync();
var connectionRecord = await _walletRecordService.GetAsync<ConnectionRecord>(agentContext.Wallet, model.ConnectionId);
if (connectionRecord == null)
{
ModelState.AddModalError("", "Invalid connection Id.");
return View(model);
}
var proofNameRequest = await CreateProofNameMessage(connectionRecord);
if (!proofNameRequest.VerifyFirstName(model.HolderFirstName))
{
ModelState.AddModalError(nameof(model.HolderFirstName), "Invalid first name.");
return View(model);
}
await _messageService.SendAsync(agentContext.Wallet, proofNameRequest, connectionRecord);
return RedirectToAction("Index");
}
return View(model);
}
I keep getting this error:
The model item passed into the dictionary is of type 'OutsourcedTicketPlatform.UI.ViewModels.Home.AccountSearchViewModel', but this dictionary requires a model item of type 'OutsourcedTicketPlatform.UI.ViewModels.Home.AccountDetailsViewModel'.
Home controller:
public class HomeController : Controller
{
[Authorize]
public ActionResult Index()
{
return View();
}
[Authorize]
public ActionResult SearchResults(AccountSearchViewModel model)
{
if (ModelState.IsValid)
{
AccountDetailsViewModel accountDetails = new AccountDetailsViewModel(model.CustomerReferenceNumber);
return View(accountDetails);
}
return View("Index");
}
[Authorize]
public ActionResult MobileResults(AccountDetailsViewModel model)
{
if (ModelState.IsValid)
{
AccountDetailsViewModel accountDetails = new AccountDetailsViewModel(model.CustomerReferenceNumber);
return View(accountDetails);
}
return View("Index");
}
}
MobileIssueReporterview:
#model OutsourcedTicketPlatform.UI.ViewModels.Home.AccountDetailsViewModel
#{
ViewBag.Title = "Mobile Issue Reporter";
}
<h2>Mobile Issue Reporter</h2>
<p>Hi (CustomerName) are you phoning today to log the mobile device as lost or stolen?</p>
<p>"Please Confirm your mobile number"</p>
<p>#Html.TextBox("mobileNumber")</p>
Search results view (this navigates to the mobile issue reporter)
#model OutsourcedTicketPlatform.UI.ViewModels.Home.AccountDetailsViewModel
#{
ViewBag.Title = "Key Account Management";
}
<fieldset>
<legend>#ViewBag.Title</legend>
<p>Please provide the account name:</p>
#foreach (var item in Model.AccountContacts)
{
#Html.RadioButton("AccountContact", item) #item
}
<input id="ContactNotListedButton" type="button" value="Contact name not on list" />
<p>Please provide the first line of the billing address:</p>
#Html.RadioButton("BillingAddressFirstLine", Model.BillingAddressFirstLine, false) #Model.BillingAddressFirstLine
<input id="NoMatchingDetailsButton" type="button" value="No Matching Details" />
#* 1 = Unicom, 2 = Titan *#
#if (Model.AccountType == 1 || Model.AccountType == 2)
{
<input id="NextButton" type="button" value="Next" />
}
#if (Model.AccountType == 1 && Model.IsKeyAccount && Model.HasActiveMobileContracts)
{
using (Html.BeginForm("MobileResults", "Home", FormMethod.Post))
{
#Html.Hidden("CustomerReferenceNumber","123456")
#Html.Hidden("customerName", "John Smith")
#Html.Hidden("mobileNumber", "123456789")
<input type="submit" value="Mobile Lost or Stolen?" />
}
}
</fieldset>
The error is happening when I click on the Mobile Lost or Stolen? button
It Seems You are passing populated values with the model AccountSearchViewModel but that view is expecting data from AccountDetailsViewModel chek with AccountDetailsViewModel model it will work fine.
I have the following viewModel
public class ExerciceViewModel
{
public string Code { get; set; }
public string Titre { get; set; }
public int QuestionCourante { get; set; }
}
the following view
#model MonEcoleVirtuelle.ViewModel.ExerciceViewModel
#{
ViewBag.Title = "Test";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Test</h2>
#using (Html.BeginForm("test", "exercice", FormMethod.Post))
{
#Model.Code <br />
#Model.Titre<br />
#Model.QuestionCourante<br />
<br />
<br />
Model.Code = "Code Modifie";
<input type="submit" value="Post Moi Ca!" name="fini" />
}
and the following controller methods
[HttpPost]
public ActionResult Test(ViewModel.ExerciceViewModel model)
{
if (ModelState.IsValid)
{
return Content(model.Code);
}
return View(model);
}
[HttpGet]
public ActionResult Test()
{
var vm = new ViewModel.ExerciceViewModel { Code = "code1", Titre = "Mon titre", QuestionCourante = 1 };
return View(vm);
}
When I submit the form, the model passed is empty, all properties are reset, not keeping the original values. What am I missing.
thanks
well, instead of #Model.Code which just display the values, you need some inputs.
So #Html.TextBoxFor(m => m.Code) for example
To manage a collection, you can do something like that :
#for (var i = 0; i < Model.Collection.Count; i++) {
Html.TextBoxFor(m => Model.Collection[i].Property)
}
You have not included any input fields in your view.
The #Model.Code etc only output the value of the field. To be able to post back elements they need to be form elements, like inputs. Use something like
#Html.TextBoxFor(p=>p.Code)
to create input fields that can then be posted back.
For a more complete guide see MSDN at http://msdn.microsoft.com/en-us/library/dd410596(v=vs.100).aspx
I have got the two buttons in the same view one is working with the data to show in a label in another view and I have written the function for the button2 (adding another value), when I click on the button2 its not showing the data in view ..... rather it's giving error like this ... http:404 Resource not found error
and this is the view
#model MvcSampleApplication.Models.products
#{
ViewBag.Title = "Valuesadd";
}
<h2>Valuesadd</h2>
#using (Html.BeginForm("SubmitValue","EnterValue",FormMethod.Post))
{
<div>
<fieldset>
<legend>Enter Textbox Value</legend>
<div class ="editor-label">
#Html.LabelFor(m => m.EnteredValue)
</div>
<div class="editor-field">
#Html.TextBoxFor(m=>m.EnteredValue)
</div>
<p>
<input type="submit" value="Submit1" />
</p>
</fieldset>
</div>
}
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
<p>
<input type="submit" value="Submit2" />
</p>
}
and this is the controller for
namespace MvcSampleApplication.Controllers
{
public class EnterValueController : Controller
{
[HttpPost]
public ActionResult SubmitValue(MvcSampleApplication.Models.products model)
{
TempData["logindata"] = model.EnteredValue;
return RedirectToAction("submittedvalues" , "SubmitValue2");
// how can we redirect to another view when the button is clicked in one view
}
public ActionResult submittedvalues()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = data;
return View(model);
}
// action for second button click
public ActionResult submittedvalues2()
{
var model = new MvcSampleApplication.Models.category();
string data = TempData["logindata"] != null ? TempData["logindata"].ToString() : "";
model.lablvalue = "HIIII"+data;
return View(model);
}
}
}
would you pls suggest any idea ..
Many thanks...
Your form action and action in the controller are not named the same. Also you don't have a HttpPostfor it
#using (Html.BeginForm("SubmitValue2","EnterValue",FormMethod.Post))
{
}
//add this
[HttpPost]
public ActionResult submittedvalues2()
{
var model = SOMETHING;
return View("submittedvalues", model);
}
or
[HttpPost]
public ActionResult submittedvalues2()
{
//Do your post actions and redirect to action
return RedirectToAction("submittedvalues");
}
SubmitValue2 in the form should be submittedvalues2, and add a HttpPost attribute on it