submit button doesn't post data while using jquery.validation.js - asp.net-mvc

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.

Related

When updating user information viewmodel is null

Error: NullReferenceException: Object reference not set to an instance of an object.
Web.Controllers.ManageController.ChangeUser(BaseViewModel model) in ManageController.cs
+
user.FirstName = model.ChangeUserViewModel.FirstName;
I cannot understand why I am getting this error, could you please help me find what I am doing wrong ?
What i am trying to achieve is updating the user information trough my viewmodel.
Can you please advise if the way i am trying to do it is correct?
BaseViewModel:
public class BaseViewModel
{
public IndexViewModel IndexViewModel { get; set; }
public ChangeUserViewModel ChangeUserViewModel { get; set; }
}
ChangeUserViewModel:
public class ChangeUserViewModel
{
[Required]
[StringLength(20, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 1)]
public string FirstName { get; set; }
[Required]
[StringLength(20, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 1)]
public string LastName { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Display(Name = "Profile Picture")]
[DataType(DataType.Upload)]
[MaxFileSize(5* 1024 * 1024)]
[AllowedExtensions(new string[] { ".jpg", ".png", ".jpeg", ".gif", ".tif" })]
public IFormFile ProfilePicture { get; set; }
}
Controller:
public async Task<IActionResult> Index()
{
var user = await GetCurrentUserAsync();
var model = new BaseViewModel
{
IndexViewModel = new IndexViewModel
{
HasPassword = await _userManager.HasPasswordAsync(user),
PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user),
Logins = await _userManager.GetLoginsAsync(user),
BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user),
AuthenticatorKey = await _userManager.GetAuthenticatorKeyAsync(user),
},
ChangeUserViewModel = new ChangeUserViewModel
{
FirstName = user.FirstName,
LastName = user.LastName,
Email = user.Email
}
};
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ChangeUser(BaseViewModel model)
{
if (!ModelState.IsValid)
{
return RedirectToAction("Index", "Manage");
}
var user = await GetCurrentUserAsync();
if (user != null)
{
user.FirstName = model.ChangeUserViewModel.FirstName;
user.LastName = model.ChangeUserViewModel.LastName;
user.Email = model.ChangeUserViewModel.Email;
await _userManager.UpdateAsync(user);
}
return View("Index", model);
}
View:
#model BaseViewModel
#inject UserManager<ApplicationUser> UserManager
#{
ViewData["Title"] = "Manage your account";
}
<h2 class="content-heading pt-0">
<i class="fa fa-fw fa-user-circle text-muted mr-1"></i> User Profile
</h2>
<form asp-controller="Manage" asp-action="ChangeUser" method="post" class="form-horizontal" role="form" enctype="multipart/form-data">
<div class="row push">
<div class="col-lg-4">
<p class="text-muted">
Your account’s vital info.
</p>
</div>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="col-lg-8 col-xl-5">
<div class="form-group">
<label for="dm-profile-edit-firstname">Firstname</label>
<input asp-for="ChangeViewModel.FirstName" type="text" class="form-control" id="dm-profile-edit-firstname" name="dm-profile-edit-firstname" >
</div>
<div class="form-group">
<label for="dm-profile-edit-lastname">Lastname</label>
<input asp-for="ChangeViewModel.LastName" type="text" class="form-control" id="dm-profile-edit-lastname" name="dm-profile-edit-lastname">
</div>
<div class="form-group">
<label for="dm-profile-edit-email">Email Address</label>
<input asp-for="ChangeViewModel.Email" type="email" class="form-control" id="dm-profile-edit-email" name="dm-profile-edit-email">
</div>
<div class="form-group">
<label>Your Avatar</label>
<div class="push">
<img class="img-avatar" src="#Url.Action("ProfilePicture", "Account" )" alt="">
</div>
<div class="custom-file">
<input asp-for="ChangeViewModel.ProfilePicture" type="file" class="custom-file-input js-custom-file-input-enabled" data-toggle="custom-file-input" id="ProfilePicture" name="ProfilePicture">
<label class="custom-file-label" for="ProfilePicture">Choose a new avatar</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-alt-primary">
<i class="fa fa-check-circle mr-1"></i> Update Profile
</button>
</div>
</div>
</div>
</form>
It seems the controller didn't recieve the BaseViewModel when do post request from view. I suggest you could use Newtonsoft’s Json.NET instead of System.Text.Json.
Step1. Install the following Nuget package
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson
Step2.
If you are migrating from an existing project you’ll have a call to “AddMvc()” which you can then tack onto it like so :
services.AddMvc().AddNewtonsoftJson();
However in new .NET Core 3+ projects, you have a different set of calls replace MVC. So you’ll probably have one of the following :
services.AddControllers().AddNewtonsoftJson();
services.AddControllersWithViews().AddNewtonsoftJson();
services.AddRazorPages().AddNewtonsoftJson();
Then, place your breakpoint in your controller code to check the value of BaseViewModel model.

Displaying List of Uploaded Files

I have a form where users can upload files and then view a list of their uploads. I'm running into two issues:
List of files isn't appearing when page loads. The SQL Query is valid.
When user uploads a file, a NullReferenceException because the file list model isn't being loaded. I'm not sure how to pass this model into view after the upload. Any advice is greatly appreciated.
Controller for fetching list of datasets is below. The controller for uploading datasets is different, of course, but it accepts an HttpPostedFileBase and a datasetName. It only returns ViewBag.error/ViewBag.message.
public ActionResult upload(DatasetViewModel model)
{
List<DatasetDetail> model2 = new List<DatasetDetail>();
var connectionstring = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
using (SqlConnection con = new SqlConnection(connectionstring))
try
{
// Your code
con.Open();
using (SqlCommand cmd = new SqlCommand("", con))
{
cmd.CommandText = "SELECT datasetid, datasetname, timestamp FROM datasets WHERE userid = #userid";
cmd.Parameters.Add("#userid", SqlDbType.Text);
cmd.Parameters["#userid"].Value = System.Web.HttpContext.Current.User.Identity.GetUserId();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
var u = new DatasetDetail();
u.datasetid = reader["datasetid"].ToString();
u.dataset = reader["datasetname"].ToString();
/* u.timestamp = Convert.ToDateTime(reader["TIMESTAMP"]);*/
model2.Add(u);
}
}
}
catch
{
// Catch exception
}
finally
{
// Close the connection
con.Close();
}
model.datasetlist = model2;
return View(model);
}
View:
#model WebApplication12.Models.DatasetViewModel
<div style="width: 320px;">
<h2>Manage Datasets</h2>
Download Excel Template
#using (Html.BeginForm("upload", "Dashboard", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="form-group">
<label>Dataset Name:</label>
<br />
<input type="text" id="datasetname" name="datasetname" />
</div>
<div class="form-group">
<input type="file" id="dataFile" name="upload" />
</div>
<div class="form-group">
<input type="submit" value="submit" class="btn btn-block" />
</div>
}
</div>
<div id="response"></div>
#if (ViewBag.Message != null)
{
<div class="alert alert-success" role="alert">#Html.Raw(ViewBag.Message)</div>
}
#if (ViewBag.Error != null)
{
<div class="alert alert-error" role="alert">#Html.Raw(ViewBag.Error)</div>
}
<div>
#foreach (var u in Model.datasetlist)
{
<b>u.dataset</b>
}
</div>
Relevant Models:
public class DatasetViewModel
{
public List<DatasetDetail> datasetlist { get; set; }
}
public class DatasetDetail
{
public string datasetid { get; set; }
public string dataset { get; set; }
/* public DateTime timestamp { get; set; }*/
}

Updating View with changed ViewModel after Form Post

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>

How to pass a complex model back to the controller in asp.net mvc

New to web development.
I have a view that allows user to select an excel file.
When submit "preview" button is pressed file is read and data is sent back to the user to preview the data.
Then I want to be able send the model back to the control for db upload.
(this is the part I'm struggling with).
ViewModel:
public class UploadItemsViewModel
{
public List<Item> Items { get; set; }
public int CompanyID { get; set; }
public Company Company { get; set; }
public HttpPostedFileBase upload { get; set; }
public UploadJournalsViewModel()
{
Items = new List<Item>();
}
}
Controller:
public ActionResult Upload(FormCollection formCollection, int CompanyID)
{
if (Request != null)
{
HttpPostedFileBase file = Request.Files["UploadedFile"];
if ((file != null) && (file.ContentLength > 0) && !string.IsNullOrEmpty(file.FileName))
{
string fileName = file.FileName;
string fileContentType = file.ContentType;
byte[] fileBytes = new byte[file.ContentLength];
var data = file.InputStream.Read(fileBytes, 0, Convert.ToInt32(file.ContentLength));
}
}
UploadItemsViewModel itmViewModel = new UploadItemsViewModel { Company = db.Companies.Find(CompanyID), CompanyID = CompanyID };
return View(itmViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(UploadItemsViewModel itmViewModel, string Preview, string Upload)
{
if (ModelState.IsValid)
{
if (itmViewModel.upload != null && itmViewModel.upload.ContentLength >0)
{
try
{
itmlViewModel.Items = App.Services.ItemsMassUploadFileRead.ReadExcelFile(itmViewModel.upload, db.Companies.Find(itmViewModel.CompanyID));
if (string.IsNullOrEmpty(Preview))
{
foreach (var itm in itmViewModel.Items)
{
itm.StartDate = DateTime.Today;
itm.CompanyID = itmViewModel.CompanyID;
itm.User = null;
itm.Items.Add(itm);
db.SaveChanges();
}
return View();
}
else
{
return View(itmViewModel);
}
} }
catch (Exception ex)
{
ModelState.AddModelError("File", ex.Message.ToString());
return View(itmViewModel);
}
}
else
{
ModelState.AddModelError("File", "Please Upload Your file");
}
}
return View(itmViewModel);
}
View:
#using (Html.BeginForm("Upload", "ItemsUpload", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.CompanyID)
<div class="form-group">
<div class="input-group">
<label class="input-group-btn">
<span class="btn btn-default">
Browse… <input type="file" style="display: none;" accept=".xlsx" name="upload">
</span>
</label>
<input type="text" class="form-control " readonly>
</div>
<span class="help-block">
Please use a provided Excel template
</span>
</div>
<div class="form-group">
<input type="submit" value="Preview" name ="Preview" class="btn btn-default" disabled style="display: none" id="submit"/>
</div>
<div class="form-group">
<input type="submit" value="Upload" name="Upload" class="btn btn-default" id="Upload" />
</div>
<div class="help-block" id="previewHelp" style="display: none">
Preview results and scroll down to upload data to the database.
</div>
if (Model.Journals.Count != 0)
{
table here to preview the upload
}
After clicking the Upload button model comes back without the "items" collection.
The Items list will be always null in the controller, because you don't rendered any input on the View with the name Items

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