Updating View with changed ViewModel after Form Post - asp.net-mvc

I'm trying to update an MVC view to display a message after a form has been posted but cannot get it working. I'm new to this so would appreciate a few pointers on what I'm doing wrong. This isn't form validation as the logic and response message won't be known until after the form has been posted and processed.
The controller action [HttpPost] public async Task<IActionResult> PlatformRecord(RecAction RecActionNotUSed) fires on the Form POST and does some codebehind logic - I then need to update the View with a Response which is only a temporary message and not stored anywhere.
The initial GET request works fine and does display the message but just cannot figure out how to do the same after a Form POST.
I've tried adding ModelState.Clear(); without success. Also, if I redirect to the initial view I lose the Response message eg return RedirectToAction("PlatformRecord"); means I no longer have RecAction.Response = "NEED TO SHOW THIS RESPOSNE MESSAGE AFTER FORM POST.";
My code is as follows
VIEWMODEL:
public class RecAction
{
public RecUser RecUser { get; set; }
public string Response { get; set; }
}
CONTROLLER:
public class RecordManagerController : Controller
{
private readonly IOptions<ConnectionStrings> _connectionStrings;
private readonly UserManager<AppRecationUser> _userManager;
Public RecordManagerController(UserManager <AppRecationUser> UserManager,
IOptions <connectionStrings> connectionStrings)
{
_userManager = userManager;
_connectionStrings = connectionStrings;
}
// GET: /<controller>/
public IActionResult Index()
{
return View();
}
private Task<AppRecationUser> GetCurrentUserAsync()
{
return _userManager.GetUserAsync(HttpContext.User);
}
public async Task<IActionResult> PlatformRecord()
{
var RecordDataModel = new RecordDataModel(_connectionStrings.Value.DefaultConnection);
var user = await GetCurrentUserAsync();
RecAction RecAction = new RecAction();
RecAction.RecUser = RecordDataModel.GetRecord(user.Email, "Platform");
if (RecAction.RecUser.Record == null)
{
//Response Successfully Displayed
RecAction.Response = "No Record found";
}
return View(RecAction);
}
[HttpPost]
public async Task<IActionResult> PlatformRecord(RecAction RecActionNotUSed)
{
try
{
if (ModelState.IsValid)
{
var RecordDataModel = new RecordDataModel(_connectionStrings.Value.DefaultConnection);
var user = await GetCurrentUserAsync();
RecAction RecAction = new RecAction();
RecAction.RecUser = RecordDataModel.GetRecord(user.Email, "Platform");
RecSettings latestSettings = RecordDataModel.GetSettings();
RecKeys RecKeys = RecordDataModel.GetKey();
if (RecKeys.PrivateKey == null)
{
ModelState.Clear();
//Rsponse not updating
RecAction.Response = "NEED TO SHOW THIS RESPOSNE MESSAGE AFTER FORM POST.";
return View(RecAction);
}
return RedirectToAction("PlatformRecord");
}
Else
{
//Need to return the same view for errors so the validation is not overwritten.
return View();
}
}
catch
{
// If we got this far, something failed, redisplay form
return RedirectToAction("PlatformRecord");
}
}
}
VIEW:
#model ProjectXYZ.Models.RecordModels.RecAction
#{
ViewData["Title"] = "PlatformRecord";
}
<h2>Platform Record</h2>
<form asp-controller="RecordManager" asp-action="PlatformRecord" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-horizontal" autocomplete="off">
<p></p>
<hr />
<div class="form-group">
<label asp-for="RecUser.Record" class="col-md-2 control-label"></label>
<div class="col-md-10">
<textarea asp-for="RecUser.Record" class="form-control" cols="1" rows="8" readonly></textarea>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Response" class="text-danger" readonly/>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Request New Record</button>
</div>
</div>
</form>

Related

InvalidOperationException: Model item passed in the ViewDataDictionary is of type 'System.Object'

I encountered the problem when I was creating a Create page. Which lead me to an error message which says:
Error Message:
Im not entirely sure if my model name is correct.
Below are my following codes:
Songs Controller:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using System.Data;
using System.Data.SqlClient;
using System;
using Garcia___MVC.Models;
namespace Garcia___MVC.Controllers
{
public class SongsController : Controller
{
private const string ConnectionString =
#"*";
// GET: SongsController
[HttpGet]
public ActionResult Index()
{
DataTable dtbSongs = new DataTable();
using(SqlConnection sqlCon = new SqlConnection(ConnectionString))
{
sqlCon.Open();
SqlDataAdapter sqlDa = new SqlDataAdapter("SELECT * FROM Songs",sqlCon);
sqlDa.Fill(dtbSongs);
}
return View(dtbSongs);
}
// GET: SongsController/Create
[HttpGet]
public ActionResult Create(object model)
{
return View(model);
}
// POST: SongsController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: SongsController/Edit/5
public ActionResult Edit(int id)
{
return View();
}
// POST: SongsController/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: SongsController/Delete/5
public ActionResult Delete(int id)
{
return View();
}
// POST: SongsController/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
}
}
Create Page that can't be accessed:
#model Garcia___MVC.Models.SongsModel
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>SongsModel</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="SongID" class="control-label"></label>
<input asp-for="SongID" class="form-control" />
<span asp-validation-for="SongID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SongTitle" class="control-label"></label>
<input asp-for="SongTitle" class="form-control" />
<span asp-validation-for="SongTitle" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Artists" class="control-label"></label>
<input asp-for="Artists" class="form-control" />
<span asp-validation-for="Artists" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Album" class="control-label"></label>
<input asp-for="Album" class="form-control" />
<span asp-validation-for="Album" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
SongsModel.cs
using System;
namespace Garcia___MVC.Models
{
public class SongsModel
{
public int SongID { get; set; }
public string SongTitle { get; set; }
public string Artists { get; set; }
public string Album { get; set; }
}
}
Would appreciate any advice or tips on how I can go about this. Will be very much appreciated.
I was expecting a page which you can create the Song title, Artists, Album, and Song ID.
The return type of the action in the songsController must be SongsModel.
The type you specify at the top of the view page determines the return type.
I'm sorry for my bad english.

submit button doesn't post data while using jquery.validation.js

for using Remote validation , C# Asp .net core, I add this two libraries
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-validation#1.19.3/dist/jquery.validate.js"></script>
but these STOP submitting button and posting data.
My Model prop:
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Captions))]
[Display(Name = "Username", ResourceType = typeof(Titles))]
[Remote("ValidateUsername", "SignUp")]
[RegularExpression("^[a-zA-Z_]*$", ErrorMessageResourceName = "Wrong_Format", ErrorMessageResourceType = typeof(Captions))]
public string Username { get; set; }
and in controller:
[HttpPost]
public async Task<IActionResult> Index(SignUpViewModel model)
{
if (!ModelState.IsValid) return View(model);
var user = _mapper.Map<User>(model);
var addUserResult = await _userManager.CreateAsync(user, model.Password);
if (addUserResult.Succeeded)
{
var addRoleResult = await _userManager.AddToRoleAsync(user, RoleNames.Client);
if (addRoleResult.Succeeded)
{
var code = GenerateValidationCode();
bool sendSmsResult = _sendSms.SendSignUpValidationCode(model.PhoneNumber);
if (sendSmsResult) return RedirectToAction("ValidationCode");
}
}
return View(model);
}
//---Remote Action----
public async Task<IActionResult> ValidateUsername(string username)
{
var user = await _userManager.FindByNameAsync(username);
if (user != null) return Json(data: Messages.Username_Already_Taken);
return Json(data: true);
}
In Razor page I have:
<form method="post" id="signup" asp-action="Index" asp-controller="SignUp">
<div class="text-right mt-3">
#Html.LabelFor(r => r.Username)
<input type="text" id="username" asp-for="Username" class="form-control form-log-in">
#Html.ValidationMessageFor(r => r.Username, "", new {#class = "error"})
</div>
<div class="form-group">
<button type="submit" class="btn see-more-btn px-3 py-1 text-dark text-center text-decoration-none w-100 d-block">ثبت نام</button>
</div>
</form>
Remote validation works well, and submitting happens while libraries are commented.

Upload Image in Asp.Net Core?

I want to upload image in "wwwroot/uploads/img" folder but i get error.I wrote the following code:
Create View :
#model imageuploader.Models.Employee
<form method="post" enctype="multipart/form-data" asp-controller="Employee" asp-action="Create">
<div class="form-group">
<div class="col-md-10">
<input asp-for="FirstName" class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input asp-for="LastName" Class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input asp-for="ImageName" type="file" Class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Create" />
</div>
</div>
Model :
public class Employee
{
[Key]
public int ID { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public string ImageName { get; set; }
}
Controller
private readonly RegisterDBContext _context;
private readonly IHostingEnvironment _appEnvironment;
public EmployeeController(RegisterDBContext context, IHostingEnvironment appEnvironment)
{
_context = context;
_appEnvironment = appEnvironment;
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Employee emp)
{
if (ModelState.IsValid)
{
var files = HttpContext.Request.Form.Files;
foreach (var Image in files)
{
if (Image != null && Image.Length > 0)
{
var file = Image;
//There is an error here
var uploads = Path.Combine(_appEnvironment.WebRootPath, "uploads\\img");
if (file.Length > 0)
{
var fileName = Guid.NewGuid().ToString().Replace("-", "") + Path.GetExtension(file.FileName);
using (var fileStream = new FileStream(Path.Combine(uploads, fileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
emp.BookPic = fileName;
}
}
}
}
_context.Add(emp);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
else
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
}
return View(emp);
}
When i click on submit button i get an error (error line is marked), how can i upload image or file in Specified path?
Error:
NullReferenceException: Object reference not set to an instance of an object.
imageuploader.Controllers.EmployeeController+<Create>d__2.MoveNext() in EmployeeController.cs
var uploads = Path.Combine(_appEnvironmen.WebRootPath, "uploads\\img\\");
How can i upload image correctly in Specified path?
I Solved it. I understood i initial bad
_appEnvironment
in Constructor.
With repeated edits, all of the codes in question are currently correct.
Thanks #Shyju user.
Here is how to upload an image in C# Asp.net core Web Application 2.1 MVC:
First I'm assuming you've created a model, added to db and now working in the controller.
I've created a Person model
person model
For create get:
//Get : Person Create
public IActionResult Create()
{
return View();
}
post Action (please see screen shot)
create post action method
Finally the view
Create View
Project Output:
Here is the output of my project

Display a list in a partial view at post

I have this code in my controller:
[HttpPost]
public ActionResult Index(double userLat, double userLng)
{
var context = new weddingspreeEntities();
var coordinates = context.Venues
.Select(loc => new { vname = loc.VenueName, lat = loc.VenueLat, lng = loc.VenueLong })
.ToList();
string venueName = string.Empty;
List<SearchModel.DistLocation> venDistList = new List<SearchModel.DistLocation>();
for (int i = 0; i < coordinates.Count; i++)
{
string name = coordinates[i].vname;
double? lat = coordinates[i].lat;
double? lng = coordinates[i].lng;
var loc1Lat = lat.Value;
var loc1Lng = lng.Value;
var loc2Lat = userLat;
var loc2Lng = userLng;
double distance = TrackingHelper.CalculateDistance(
new SearchModel.Location() { Latitude = loc1Lat, Longitude = loc1Lng },
new SearchModel.Location() { Latitude = loc2Lat, Longitude = loc2Lng });
//convert kilometers to miles
double distMiles = distance * 0.621371192;
venueName = name;
venDistList.Add(new SearchModel.DistLocation() { venName = name, Distance = distMiles });
}
return View(venDistList);
}
I have this code in my view:
<div class="row">
<div class="form-group">
<div class="col-md-6">
#using (Html.BeginForm("Search", "Home", FormMethod.Post))
{
#*#Html.TextBoxFor(model => model.cityName)*#
<label>Enter City and State or Zip Code</label>
<input type="text" id="citystate" name="citystate" />
<label>Enter Your Wedding Date</label>
<input class="datefield" data-val="true" data-val-required="Date is required" id="weddingDate" name="weddingDate" type="date" value="1/11/1989" />
<label>Enter Your Guest Count</label>
<input type="text" id="guestcount" name="guestcount" />
<input type="button" id="search" name="search" value="Search for Venues" />
}
</div>
<!--This is the div where the google map will render -->
<div class="col-md-6">
<div id="map_canvas" style="height: 600px;"></div>
</div>
</div>
</div>
<div>
#Html.Partial("_SearchResults")
</div>
I have omitted some of my view for brevity
This is the partial view I am trying to render:
#model IEnumerable<WeddingSpree_Alpha.Models.SearchModel.DistLocation>
#{
Layout = null;
}
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
foreach (var item in Model)
{
#item.venName
#item.Distance
}
}
What I am trying to do is to have the user enter the values in the search box and then after the click post the results (in the list named venDistList) to the view using a foreach statement.
The model looks like this:
public class SearchModel
{
public string cityName { get; set; }
public DateTime weddingDate { get; set; }
public int guestCount { get; set; }
public class Location
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class DistLocation
{
public string venName { get; set; }
public double Distance { get; set; }
}
}
I would like the list results to populate after the button click (post) on the page. I thought my code would do that however. I get the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object'
I know that error happens when you try to use a model that is not populated yet but I thought I did that in my controller code? What exactly could be throwing that error?
This is the controller code for my partial view:
public ActionResult _SearchResults(SearchModel model)
{
return View();
}
If you are not at least instantiating an instance of IEnumerable to pass back (even if it is empty) then it will throw the null reference when you try to iterate throught the model in the partial view.
Edit: (Code trimmed down for example) Your original error is that you are trying to iterate through an object that does not exist. The below will show you how to make user of an Ajax call on your form submit to dynamically generate your partial view and attach it to your main page
Controller:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult _SearchResults(string citystate, DateTime? weddingDate, double? guestcount)
{
List<SearchModel.DistLocation> venDistList = new List<SearchModel.DistLocation>();
venDistList.Add(new SearchModel.DistLocation() { venName = "weee1", Distance = 2 });
venDistList.Add(new SearchModel.DistLocation() { venName = "weee2", Distance = 4 });
venDistList.Add(new SearchModel.DistLocation() { venName = "weee3", Distance = 6 });
return PartialView(venDistList);
}
Index.cshtml:
#{
ViewBag.Title = "Home Page";
}
#*This is our form which will feed our user input and drive our search results output*#
<div class="row">
<div class="form-group">
<div class="col-md-6">
<form id="searchMe">
<label>Enter City and State or Zip Code</label>
<input type="text" id="citystate" name="citystate" />
<label>Enter Your Wedding Date</label>
<input class="datefield" data-val="true" data-val-required="Date is required" id="weddingDate" name="weddingDate" type="date" value="1/11/1989" />
<label>Enter Your Guest Count</label>
<input type="text" id="guestcount" name="guestcount" />
<button type="submit" class="btn btn-primary">Search for Venues</button>
</form>
</div>
</div>
</div>
<div class="row">
#*This is where we want our search results to appear when user hits submit on our form*#
<div id="SearchResult"></div>
</div>
#section scripts {
<script>
$(document).ready(function () {
//When the user hit the submit button we will post the form results to our partial view controller
$('#searchMe').submit(function () {
$.ajax({
method: "POST",
url: "/Home/_SearchResults",
data: $(this).serialize(),
success: function (result) {
//When then load our partial view into our containing div on the main page
$('#SearchResult').html(result);
}
});
return false;
});
});
</script>
}
Partial View (_SearchResult.cshtml)
#model IEnumerable<deletemeweb2.Models.SearchModel.DistLocation>
#{
Layout = null;
}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Search Results</h3>
</div>
<div class="panel-body">
#if (Model != null || Model.Count() < 1)
{
using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
foreach (var item in Model)
{
<p>#item.venName</p>
<p>#item.Distance</p>
}
}
}
else
{
<p>No results found</p>
}
</div>
</div>

Post Request is not returning same object as passed

I am trying to do a simple CRUD app asp.net core using MVC and the strangest thing is happening to me.
create the model and pass it in to the form but when I go to save it, it no longer has the Id that I passed into it.
[HttpGet]
public IActionResult CreateCompany(Guid id)
{
//id = 677b57f1-d0b2-484b-9892-b06e6eb9f1f7
var pageId = id;
var company = new CompanyListItem() {PublicPageId = pageId};
return View(company);
}
[HttpPost]
public IActionResult CreateCompany(CompanyListItem model)
{
//model.PublicPageId = 00000000-0000-0000-0000-000000000000
if (ModelState.IsValid)
{
model.Id = Guid.NewGuid();
var newModel = _companyDataProvider.Add(model);
PublicPageViewModel page = null;
if (newModel != null)
{
page = _pageDataProvider.GetPageIdFromCompanyListId(newModel.Id);
}
if (page != null)
{
return RedirectToAction("Details", page);
}
}
return View();
}
my form:
#model CompanyListItem
<h1>Add Company</h1>
<form method="post">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Header"></label>
<input asp-for="Header" class="form-control"/>
</div>
<div>
<input type="submit" class="btn btn-success" value="save"/>
<a class="btn btn-default">Cancel</a>
</div>
</div>
</form>
Does anyone know why this is happening? Or how i can prevent it from happening?

Resources