I want to give user the option to change their profile picture.On hitting the save button my controller action is hit but I get null value for HttpPostedFileBase.I am uploading files first time in mvc so not able to figure out where I am doing wrong and hence getting null value in controller.
controller
[AuthenticationRequired]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChangeProfilePicture(HttpPostedFileBase imageData)
{
}
view
#using (Ajax.BeginForm("ChangeProfilePicture", "Account", new { enctype = "multipart/form-data" },new AjaxOptions { OnSuccess = "OnSuccess" }))
{
#Html.AntiForgeryToken()
<div class="modal-body" id="tilesDescription">
<div class="row">
<div class="col-md-12">
<div class="text-center">
<div class="fileUpload btn btn-primary">
<span>Select a photo from your computer</span>
<input id="uploadBtn" type="file" class="upload" name="imageData" accept="image/*" />
</div>
<div class="text-center">
<img id="imgprvw" alt="uploaded image preview" class="imgPreview hide" />
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-rounded btn-sm btn-tiles" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-rounded btn-sm btn-tiles disabled" id="btnProfilePic">Set as profile picture</button>
</div>
}
You cannot post your file using ajax like that, cause is not supported.
From my experience, the easiest way to get files posted using Ajax (if using jquery), is using :
http://malsup.com/jquery/form/
Related
In the previous question "ASP .NET Core Repository Id Article passed in was changed to 0?" I did it successfully, but due to a conflict with the team on GitHub, I had to rewrite my code. However, when I run it, I have a transmission error between Model and ViewModel. What is this and how do I fix it? I don't change anything between my code.
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditArticle(Article article)
{
if(!ModelState.IsValid)
{
return View(article);
}
if(!_studentRepository.EditArticle(article))
{
throw new ArgumentException("...");
}
return RedirectToAction("Index");
}
View
#model Megatron.ViewModels.ArticleFacultyViewModel
#{
ViewData["Title"] = "Edit Article";
}
<div>
<form asp-action="EditArticle">
<partial name="_StatusMessage" model="#ViewData["Message"]" />
<div>
#Html.HiddenFor(a => a.Article.Id)
<div class="form-group row">
<div class="col-2">
<label asp-for="Article.Title" class="col-form-label"></label>
</div>
<div class="col-5">
<input asp-for="Article.Title" class="form-control" />
</div>
</div>
<div class="form-group row">
<div class="col-2">
<label class="col-form-label">Type of contribution</label>
</div>
<div class="col-3">
<button hidden class="btn btn-primary" type="button" data-toggle="collapse" data-target="#ImportFileCollapse" aria-expanded="false" aria-controls="ImportFileCollapse">
</button>
<button hidden class="btn btn-primary" type="button" data-toggle="collapse" data-target="#TextAreaCollapse" aria-expanded="false" aria-controls="TextAreaCollapse">
</button>
<button id="button-collapse" class="btn btn-primary" type="button" data-toggle="collapse" data-target=".multi-collapse" aria-expanded="false" aria-controls="ImportFileCollapse TextAreaCollapse">
Switch to Editor
</button>
</div>
</div>
You return a Artical type model to the View in the post method,
if(!ModelState.IsValid)
{
return View(article);
}
While the view expect a
ArticleFacultyViewModel type model. You may convert it.
if(!ModelState.IsValid)
{
var articleVM = new ArticleFacultyViewModel
{
Article = article,
Faculties = _facultyRepository.GetFaculties()
};
return View(articleVM);
}
I have a submit button in index.cshtml page and when i click that button i need to go in another ActionResult server method.But it's not working.(not hitting to the server side method)
Html
#model IEnumerable<AAB.Domain.Items>
<!-- Featured Products -->
<div class="card-deck card-deck-product mt-3 mb-2 mb-sm-0">
#foreach (var item in Model)
{
<div class="card card-product" id="#item.ItemId">
<div class="card-body">
<button class="wishlist atw-demo " title="Added to wishlist"><i data-feather="heart"></i></button>
<img class="card-img-top" src="#item.ImageUrl" alt="Card image cap">
#item.ItemName
<div class="price"><span class="h5">Rs:#item.ItemPrice</span></div>
</div>
<div class="card-footer">
<input type="submit" class="btn btn-sm" id="#item.ItemId" value="Add to Cart" href="#Url.Action("AddNewItems","Home",new { ItemId=item.ItemId})"/>
</div>
</div>
}
</div>
Server side
[HttpPost]
public ActionResult AddNewItems(int ItemId)
{
// Some code here.
return PartialView("_PopCart", ItemId);
}
Surround your button with a tag.
<a href="#Url.Action("AddNewItems","Home",new { ItemId=item.ItemId})">
<input type="submit" class="btn btn-sm" id="#item.ItemId" value="Add to Cart" />
</a>
I have a login page within an ASP.NET Core App with a pop up to send a password reset email to the users email (Just using Identity):
<div class="login-body">
<div class="container">
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-signin">
<h2 class="form-signin-heading">#Localizer["Sign In"]</h2>
<div class="login-wrap">
<div class="user-login-info">
<input asp-for="Email" type="email" class="form-control" placeholder="#Localizer["Email"]" autofocus/>
<span asp-validation-for="Email" class="text-danger"></span>
<input asp-for="Password" type="password" class="form-control" placeholder="#Localizer["Password"]"/>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label class="checkbox">
<input asp-for="RememberMe"/> Remember me
<span class="pull-right">
<a data-toggle="modal" href="#forgotPassModal">Reset Password</a>
</span>
</label>
<button class="btn btn-lg btn-login btn-block" type="submit">#Localizer["Sign In"]</button>
<div class="registration">
#Localizer["No Account"]
<a asp-area="" asp-controller="Account" asp-action="Register">#Localizer["Create Account"]</a>
</div>
</div>
<!-- Modal -->
<div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="forgotPassModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Reset Password</h4>
</div>
<div class="modal-body">
<p>Enter your e-mail address below to reset your password.</p>
<input type="text" name="email" placeholder="Email" autocomplete="off" class="form-control placeholder-no-fix">
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-default" type="button">Cancel</button>
<button class="btn btn-success" asp-controller="Account" asp-action="ForgotPassword" method="post">Submit</button>
#*<input type="button" class="btn btn-success" asp-controller="Account" asp-action="ForgotPassword" formmethod="post">Submit<input>*#
</div>
</div>
</div>
</div>
<!-- modal -->
</form>
</div>
When I input the email address it does the right thing, sends an email with a code, but it redirects me to a separate view stating to go check your emails.
Is it possible to just return a message either to the popup window or login page saying the same thing?
This is the ForgotPassword Action:
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user)))
{
return View("ForgotPasswordConfirmation");
}
var code = await UserManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action(nameof(ResetPassword), "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
$"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
return View("ForgotPasswordConfirmation");
}
return View(model);
}
What you can use is TempData. TempData can hold data for one more additional request and only for one additional request. So you can store this information in the TempData. It is meant for things like your use case. It could look something like this.
public IActionResult Login()
{
var loginModel = new LoginModel();
loginModel.ForgotPassWordModel = (ForgotPassWordModel) TempData["ForgotPassword"];
return View(loginModel);
}
public IActionResult ForgotPassword()
{
if (valid)
{
TempData["ForgotPassword"] = new ForgotPassWordModel() {callbackUrl = "Go to this"};
return RedirectToAction("Login");
}
return View();
}
Here is my example LoginModel and my ForgottonPasswordModel. Ofcourse, yours will be more complicated.
public class ForgotPassWordModel
{
public string callbackUrl;
}
public class LoginModel
{
public ForgotPassWordModel ForgotPassWordModel { get; set; }
}
When someone makes a request to ForgotPassword, if it is valid, store the result in TempData and Redirect back to Login. Now you can read the TempData["ForgotPassword"] that you just set in the previous request. In my example, I put the data in my LoginModel. If there is no tempData, it would be null. Now in your view you can check for this ForgotPassword property.
#if (Model.ForgotPassWordModel != null)
{
// Show message/modal
}
The great thing about TempData is that when you set data, it is only held for one more additional request so it works for situations like these.
How do I redirect from an MVC Post Action back to the bootstrap popup modal partial view where the post came from?
Here is the PartialView sitting in the Bootstrap modal popup on the page.
It has a div with a validation taghelper waiting for any model errors.
#model CreateRoleViewModel
<div class="panel panel-primary partialModalFormDivs">
#Html.Partial("_ModalHeader",
new ModalHeader
{
Heading = "ADD ROLE",
glyphiconClass = "glyphicon glyphicon-random"
}
)
<div class="panel-body">
<div asp-validation-summary="All" class="text-danger"></div>
<form asp-action="CreateRole" method="post">
<div class="form-group">
<label asp-for="RoleName"></label>
<input asp-for="RoleName" class="form form-control" />
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Create</button>
<a asp-action="Index" class="btn btn-default">Cancel</a>
</div>
</form>
</div>
</div>
It posts to this action:
[HttpPost]
public async Task<IActionResult> CreateRole(CreateRoleViewModel createRoleViewModel)
{
if (ModelState.IsValid)
{
IdentityRole role = new IdentityRole(createRoleViewModel.RoleName);
IdentityResult result
= await _roleManager.CreateAsync(role);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
else
{
foreach (IdentityError error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
}
}
return View(createRoleViewModel);
}
I can return a PartialView like this at the end:
return View("_CreateRole", createRoleViewModel);
But then the whole page is cleared and this partial is returned with no layout file.
How can I return the results back to the modal popup window.
I understand the problem and the current behavior. But has anyone else solved this?
I think what you want to do is an ajax post and then just return a partial view and replace the form. The form should be inside a container div with an id that is used to replace its contents with the ajax post result. To do this you need to include the jquery unobtrusive ajax script which will auto wire the ajax based on the data-* attributes on the form as shown below
<div class="panel-body">
<div asp-validation-summary="All" class="text-danger"></div>
<div id="resultcontainer">
<form asp-action="CreateRole" method="post"
data-ajax="true"
data-ajax-method="POST"
data-ajax-mode="replace"
data-ajax-update="#resultcontainer"
>
<div class="form-group">
<label asp-for="RoleName"></label>
<input asp-for="RoleName" class="form form-control" />
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Create</button>
<a asp-action="Index" class="btn btn-default">Cancel</a>
</div>
</form>
</div>
</div>
and don't forget to return a partial view
return PartialView(createRoleViewModel);
I looked over some other answers and the solutions there were not working. And I couldn't seem to figure out why. This is using Bootstrap 3.0. All I am trying to do is use that to upload a new avatar image. The problem is it always comes up null and I cannot seem to figure out why.
Here is my HTML:
#using (Html.BeginForm("EditAvatar", "Profile", new { userID = #Model.ProPit_User.userID }, FormMethod.Post, new { }))
{
<div class="form-group">
<div class="fileinput fileinput-new" data-provides="fileinput">
<div class="fileinput-new thumbnail" style="width: 200px; height: 150px;">
<img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&text=no+image" alt="" />
</div>
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 150px;">
</div>
<div>
<span class="btn default btn-file">
<span class="fileinput-new">Select image
</span>
<span class="fileinput-exists">Change
</span>
<input id="avatar_image" type="file" name="..." runat="server">
</span>
<a href="#" class="btn default fileinput-exists" data-dismiss="fileinput">Remove
</a>
</div>
</div>
<div class="clearfix margin-top-10">
<span class="label label-danger">NOTE!
</span>
<span>Attached image thumbnail is supported in Latest Firefox, Chrome, Opera, Safari and Internet Explorer 10 only
</span>
</div>
</div>
<div class="margin-top-10">
<button type="submit" class="btn green">
Save Changes
</button>
<button type="reset" class="btn default">Cancel</button>
</div>
}
I have given the file input the ID of avatar_image
Here is the controller:
[HttpPost]
public ActionResult EditAvatar(HtmlInputFile avatar_image)
{
if (avatar_image.PostedFile != null)
{
//do whatever you want with the file
}
return View();
}
When looking at the break point the avatar_image.PostedFile is always null. Anyone have any idea what I am missing?
You might check the request in Fiddler. More importantly though, you need to add the enctype="multipart/form-data" attribute to the form.