Editing users in ASP.NET Core Identity - c#

I'm just trying to make an Edit page for my Identity database. I'm using Razor Pages, and I'm new to it. I found some solutions for MVC, but they don't really work for me because of using Views and other stuff like Controllers. I have a main page Index.cshtml, where I can choose the users from a list like the image below
And delete them by clicking a submit button.
I handeled deletion like this:
CSHTML file:
<button type="submit" class="btn btn-sm btn-danger" asp-route-id="#user.Id" asp-page-handler="Del">Del</button>
<button type="submit" class="btn btn-sm btn-primary" asp-route-id="#user.Id" asp-page-handler="Change">Change</button>
CSHTML.CS file:
public ApplicationUser ApUser { get; set; }
public async Task<ActionResult> OnPostDel(string id)
{
ApUsers = _userManager.Users.ToList();
ApUser = await _userManager.FindByIdAsync(id);
if (ApUser != null)
{
IdentityResult result = await _userManager.DeleteAsync(ApUser);
}
//return RedirectToAction("UserChange/Index");
return RedirectToPage("Index");
}
And it works just fine by me, but I need to Edit too. So my Edit POST method in Index.cshtml.cs looks like:
public async Task<ActionResult> OnPostChange(string id)
{
ApUsers = _userManager.Users.ToList();
ApUser = await _userManager.FindByIdAsync(id);
if (ApUser == null)
{
return NotFound();
}
else return RedirectToPage("Edit");
}
And my Edit.cshtml.cs look like this:
<form asp-action="Edit" asp-controller="Users">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<input type="hidden" asp-for="Id" />
</div>
<div class="form-group">
<label asp-for="Email" class="control-label">Email</label>
<input type="text" asp-for="Email" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Score" class="control-label">Score</label>
<input type="number" asp-for="Score" class="form-control" />
</div>
...
<div class="form-group">
<input type="submit" asp-page-handler="Edit" value="Save" class="btn btn-default" />
</div>
</form>
And Edit.cshtml.cs:
public async Task<IActionResult> OnPostEdit(string id)
{
if (ModelState.IsValid)
{
ApUser = await _userManager.FindByIdAsync(id);
if (ApUser != null)
{
ApUser.Email = Email;
ApUser.UserName = Email;
ApUser.Score = Score;
ApUser.Position = Position;
ApUser.Sequence = Sequence;
var result = await _userManager.UpdateAsync(ApUser);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
else
{
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
}
}
return RedirectToAction("Index");
}
And it doesn't work of course. I'm just trying to remake some MVC example to Razor Pages. Maybe you have better solutions for this, but I really stuck here.

So, yeah, I just made a button on my Index.cshtml page like this, it provides asp-route-id to Edit page:
<a asp-page="Edit" class="btn btn-sm btn-primary" asp-route-id="#user.Id">Edit</a>
Made an InputModel on Edit.cshtml.cs file:
public InputModel Input { get; set; }
public class InputModel
{
[Required(ErrorMessage ="{0} не может быть пустым")]
[EmailAddress(ErrorMessage ="Неверный формат {0}")]
[Display(Name = "Email")]
public string Email { get; set; }
[Required(ErrorMessage = "Введите {0}")]
[StringLength(5, ErrorMessage = "{0} должна быть из {1} символов", MinimumLength = 5)]
[Display(Name = "Последовательность")]
public string Sequence { get; set; }
...
}
Just added in Edit.cshtml file #page "{id}", to provide it through previous page
OnPost method provides User changes from the model:
public async Task<IActionResult> OnPostAsync(string id)
{
ApUser = await _userManager.FindByIdAsync(id);
if (!ModelState.IsValid)
{
return Page();
}
ApUser.Email = Input.Email;
ApUser.Score = Input.Score;
ApUser.Sequence = Input.Sequence;
ApUser.Position = 0;
await _userManager.UpdateAsync(ApUser);
Message = ApUser.Email;
return RedirectToPage("Index");
}
And the I just use a model in Edit.cshtml
<form method="post" asp-route-id="#Model.ApUser.Id">
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" value="#Model.ApUser.Email.ToString()" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
...
<button type="submit" class="btn btn-default">Save</button>
</form>

Related

Upload File with IFormFile .NET Core MVC is showing error of Required File

After Selecting the file form Choos File, submitting the form showing error "The formFile field is required."
Model is here:
In Debug mode formFile value is set; it shows null;
public class FileUploadTest
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
[NotMapped]
public IFormFile formFile { get; set; }
public string fromFileUrl { get; set; }
}
View is here:
#model UdyogWeb.Models.FileUploadTest
#{
ViewData["Title"] = "Create";
}
<div class="row">
<div class="col-md-4">
<form asp-action="Create" asp-controller="FileUploadTests" enctype="multipart/form-data" method="post">
<div asp-validation-summary="All" class="text-danger" ></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="formFile" class="control-label">Upload File</label>
<input asp-for="formFile" class="form-control" />
<span asp-validation-for="formFile" class="text-danger"></span>
</div>
#* <div class="form-group">
<label asp-for="fromFileUrl" class="control-label"></label>
<input asp-for="fromFileUrl" class="form-control" />
<span asp-validation-for="fromFileUrl" 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");}
}
Controller is here:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,fromFileUrl")] FileUploadTest fileUploadTest)
{
string folderurl = " ";
if (ModelState.IsValid)
{
if (fileUploadTest.formFile != null)
{
folderurl = "casefile/brieforwrit/";
folderurl += Guid.NewGuid().ToString() + fileUploadTest.formFile.FileName;
//fileUploadTest.fromFileUrl = folderurl;
string serverfolderurl = Path.Combine(_webHostEnvironment.WebRootPath, folderurl);
using (FileStream fs = new FileStream(serverfolderurl, FileMode.Create))
{
await fileUploadTest.formFile.CopyToAsync(fs);
}
}
fileUploadTest.fromFileUrl = folderurl;
fileUploadTest.Id = Guid.NewGuid();
_context.Add(fileUploadTest);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(fileUploadTest);
}
In this project, I uploaded some files on the Identity Rejor page and it's working perfectly.
Please help to solve this error
Thank you so much for your attention and participation.
In Debug mode formFile value is set; it shows null;
You need to bind your formFile too.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,fromFileUrl,formFile")] FileUploadTest fileUploadTest)
{...}
result:

form for a model that contains a list property in asp.net core 3 MVC

I'm trying to create a form in asp.net core 3 MVC.
the model is a "package" class that contains different properties about the package, and a List<item> items property of the items in the package , item is a class defined that contains different properties of an "item".
how should I approach creating a form for the user to add a new "package" ?
plus inserting the items inside it, which could be any amount of items , I would like the user to insert a row for each item (with a button that adds new input row for a new item ) and submit it with the final form .
any help would be appreciated.
Here is a whole working demo:
Model:
public class Package
{
public int Id { get; set; }
public string Name { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public int Id { get; set; }
public string ItemName { get; set; }
}
View:
#model Package
<h1>Create</h1>
<h4>Package</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="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<button onclick="addRow()" type="button">Add Row</button>
<table id="AddItemsTable">
<tr>
<th>#Html.DisplayNameFor(model=>model.Items[0].ItemName)</th>
</tr>
</table>
<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>
JS:
#section Scripts {
<script>
var counter = 0;
function addRow() {
var table = document.getElementById("AddItemsTable");
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
cell1.innerHTML = '<input type="text" name="Items[' + counter+'].ItemName"/>';
counter++;
}
</script>
}
Controller:
// GET: Packages/Create
public IActionResult Create()
{
return View();
}
// POST: Packages/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Package package)
{
if (ModelState.IsValid)
{
_context.Add(package);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(package);
}
Result:

Adding a new child data item with Razor Pages, AJAX and and Entity Framework Core

Coming from ASP.NET WebForms and feeling a bit overwhelmed. I have an ASP.NET Core Razor Page that loads an incident and all the comments related to that incident. I figured out how to refresh the comments with a partial Razor Page and AJAX, but also want to add a new comment with AJAX and refresh the comments.
Models:
public class Incident
{
public Incident()
{
Comments = new HashSet<Comment>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int IncidentId { get; set; }
public int Id { get; set; }
public string CommentText { get; set; }
public virtual Incident Incident { get; set; }
}
Incident.cshtml:
#page
#model MyNamespace.IncidentModel
#{
ViewData["Title"] = "Emergency Operations Center";
}
<h4>#Html.DisplayFor(model => model.Incident.Title)</h4>
#Html.HiddenFor(model => model.Incident.Id)
<hr />
<form method="post" data-ajax="true" data-ajax-method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<input type="hidden" asp-for="Incident.Id" />
<div class="col form-group">
<label asp-for="NewComment.CommentText" class="control-label"></label>
<input asp-for="NewComment.CommentText" class="form-control" />
<span asp-validation-for="NewComment.CommentText" class="text-danger"></span>
</div>
<div class="col form-group">
<label asp-for="NewComment.EocDept" class="control-label"></label>
<input asp-for="NewComment.EocDept" class="form-control" />
<span asp-validation-for="NewComment.EocDept" class="text-danger"></span>
</div>
<div class="col-auto form-group align-self-end">
<input type="submit" value="Add Comment" class="btn btn-primary" />
</div>
</div>
</form>
<button id="getComments" class="btn btn-sm btn-outline-primary"><i class="fas fa-sync-alt"></i> Refresh Comments</button>
<div id="comments" class="mt-3">
<partial name="_CommentsPartial" model="Model.Incident.Comments.ToList()" />
</div>
<div class="mt-4">
<a asp-page="./Index">Back to Incident list</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$(function () {
$('#getComments').on('click', function () {
$('#comments').load('/Incident?handler=CommentsPartial&id=' + #Model.Incident.Id.ToString());
});
});
</script>
}
#model List<Models.Comment>
<table class="table table-sm table-striped">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().EocDept)</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().EnterDateTime)</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().EnteredBy)</th>
<th>#Html.DisplayNameFor(model => model.FirstOrDefault().CommentText)</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.EocDept)</td>
<td>#Html.DisplayFor(modelItem => item.EnterDateTime)</td>
<td>#Html.DisplayFor(modelItem => item.EnteredBy)</td>
<td>#Html.DisplayFor(modelItem => item.CommentText)</td>
</tr>
}
</tbody>
</table>
Page model in Incident.cshtml.cs
public class IncidentModel : PageModel
{
private readonly MyDbContext _context;
public IncidentModel(MyDbContext context)
{
_context = context;
}
public Incident Incident { get; set; }
[BindProperty]
public Comment NewComment { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
return NotFound();
Incident = await _context.Incidents.FirstAsync(m => m.Id == id);
if (Incident == null)
return NotFound();
LoadSortedComments();
return Page();
}
public async Task<PartialViewResult> OnGetCommentsPartialAsync(int id)
{
Incident = await _context.Incidents.FirstAsync(m => m.Id == id);
LoadSortedComments();
return Partial("_CommentsPartial", Incident.Comments.ToList());
}
public void LoadSortedComments()
{
var entry = _context.Entry(Incident);
entry.Collection(e => e.Comments)
.Query()
.OrderByDescending(c => c.EnterDateTime)
.Load();
}
public async Task<IActionResult> OnPost(int id)
{
if (!ModelState.IsValid)
{
return Page();
}
// Is this the correct way to add the new Comment?
NewComment.IncidentId = id;
_context.Comments.Add(NewComment);
await _context.SaveChangesAsync();
// How do I refresh _CommentsPartial, and what gets returned here?
return ?????;
}
}
Questions:
Is using the bound NewComment property the right way to get the new comment? (It is being added to the database, anyway.)
Is getting the Incident ID from the parameter in OnPost the right way to reference the page's incident?
What do I return from OnPost if I don't want to reload the entire page?
You could load related data using Include like below;
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
return NotFound();
Incident = await _context.Incidents.Include(i=>i.Comments).FirstOrDefaultAsync(m => m.Id == id);
if (Incident == null)
return NotFound();
return Page();
}
You could add a related entity like below
public async Task<IActionResult> OnPost(int id)
{
if (!ModelState.IsValid)
{
return Page();
}
Incident = await _context.Incidents.Include(i=>i.Comments).FirstAsync(i => i.Id == id);
NewComment.EnterDateTime = DateTime.Now;
Incident.Comments.Add(NewComment);
await _context.SaveChangesAsync();
return RedirectToPage("Incident","", new { id= Incident.Id});
}
What do I return from OnPost if I don't want to reload the entire page?
You could add data-ajax-success in your form and add the function in like below:
<form method="post" data-ajax="true" data-ajax-method="post" data-ajax-complete="successed">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<input type="hidden" asp-for="Incident.Id" />
<div class="col form-group">
<label asp-for="NewComment.CommentText" class="control-label"></label>
<input asp-for="NewComment.CommentText" class="form-control" />
<span asp-validation-for="NewComment.CommentText" class="text-danger"></span>
</div>
<div class="col form-group">
<label asp-for="NewComment.EocDept" class="control-label"></label>
<input asp-for="NewComment.EocDept" class="form-control" />
<span asp-validation-for="NewComment.EocDept" class="text-danger"></span>
</div>
<div class="col-auto form-group align-self-end">
<input id="" type="submit" value="Add Comment" class="btn btn-primary" />
</div>
</div>
</form>
#section Scripts {
<script type="text/javascript" src="~/lib/jquery-validation-unobtrusive/jquery.unobtrusive-ajax.js"></script>
<script>
successed = function (result) {
$('#comments').html(result);
}
</script>
}
Reference:https://www.learnrazorpages.com/razor-pages/ajax/unobtrusive-ajax

Why is my data binding not working and is always null?

I am trying to add data to the database. I experimenting with Blazor and .NET core:
This is my code in the controller:
[Route("AddCarBlazor")]
[HttpPost]
public IActionResult PostBlazor(Car car)
{
if (car.CarId == 0)
{
// New
car.Created = DateTime.Now;
_context.Cars.Add(car);
_context.SaveChanges();
return Ok();
}
else
{
// Update
var c = _context.Cars.First(e => e.CarId == car.CarId);
c.Brand = car.Brand;
c.Color = car.Color;
c.Model = car.Model;
c.LastChange = DateTime.Now;
c.TopSpeed = car.TopSpeed;
_context.SaveChanges();
return Ok();
}
}
My car model looks like this:
public class Car
{
[Key]
public long CarId { get; set; }
public string Created { get; set; }
public string LastChange { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public string Color { get; set; }
public long TopSpeed { get; set; }
}
I call this method like this:
private async Task AddCar()
{
await Http.PostJsonAsync(baseUrl + "/AddCarBlazor/", carobject);
await Refresh();
}
When I fill in the form and press add button the car object is always null
This is my form with the databinding:
<form>
<div class="row">
<div class="form-group col-sm-3">
<label>Brand</label>
<input input type="text" #bind="#carobject.Brand" class="form-control" placeholder="Enter brand" />
</div>
</div>
<div class="row">
<div class="form-group col-sm-3">
<label>Model</label>
<input type="text" #bind="#carobject.Model" class="form-control" placeholder="Enter model" />
</div>
</div>
<div class="row">
<div class="form-group col-sm-3">
<label>Color</label>
<input type="text" #bind="#carobject.Color" class="form-control" placeholder="Enter color" />
</div>
</div>
<div class="row">
<div class="form-group col-sm-3">
<label>TopSpeed</label>
<input type="number" #bind="#carobject.TopSpeed" class="form-control" placeholder="Enter speed" />
</div>
</div>
<div class="btn-group mr-2">
<button class="btn btn-danger mr-1" onclick=#AddCar>Save changes</button>
</div>
</form>
I have put a breakpoint on the addCar method. I get the values from the fields but when it goes to the controller it becomes null.
I have following this tutorial:
https://learn.microsoft.com/en-us/aspnet/core/blazor/call-web-api?view=aspnetcore-3.0
How can I save the values from the fields and send it to the database?
I test a demo which works well, you could refer to my code below:
1.Car.cs (namespace Blazor.Models)
public class Car
{
public long CarId { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
}
2. AddCar.razor
#page "/car"
#using System.Net.Http
#inject HttpClient Http
#using Blazor.Models
<Editform Model="carobject">
<div class="row">
<div class="form-group col-sm-3">
<label>Brand</label>
<input #bind="#carobject.Brand" class="form-control" placeholder="Enter brand" />
</div>
</div>
<div class="row">
<div class="form-group col-sm-3">
<label>Model</label>
<input #bind="#carobject.Model" class="form-control" placeholder="Enter model" />
</div>
</div>
<div class="btn-group mr-2">
<button class="btn btn-danger mr-1" onclick="#AddCar">Save changes</button>
</div>
</Editform>
#functions {
[Parameter]
private Car carobject { get; set; } = new Car();
private async Task AddCar()
{
await Http.PostJsonAsync(baseUrl + "/AddCarBlazor/", carobject);
//await Refresh();
}
}
3.Web API CORS configuration:
app.UseCors(corsbuilder => {
corsbuilder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
});
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
4.action:
[Route("AddCarBlazor")]
[HttpPost]
public IActionResult PostBlazor([FromBody]Car car)
After a weekend of research I have the solution!
I have changed my method in CarService.cs like this:
public async Task AddCar(Car car)
{
var client = new HttpClient { BaseAddress = new Uri("https://localhost:44369/api/car/") };
await client.SendJsonAsync(HttpMethod.Post, "AddCar", car);
}
Then I call this method in my razor page like this:
async Task AddCar()
{
await CarService.AddCar(car);
car = new CarService.Car();
await LoadCarData();
}
I also made a new object of the service like this:
CarService.Car car = new CarService.Car();
And I moved the model of Car.cs into CarService.cs

Passing a file to server in asp.net core with ViewModel

I'm trying to upload the file to the server using angularjs and Asp.Net Core. I'm trying to pass the file from form as a property of a view model, but it keeps coming to the server as null. It passes the model validation but there is no file in the data coming from the the client side. Could you tell me what I'm doing wrong? Or maybe this is not a valid way to post a file whatsoever? Thanks in advance.
C# code:
[HttpPost("")]
public async Task<IActionResult> Post([FromBody]PartnersViewModel thePartner)
{
if (ModelState.IsValid)
{
var file = thePartner.file;
var parsedContentDisposition =
ContentDispositionHeaderValue.Parse(file.ContentDisposition);
var filename = Path.Combine(_environment.WebRootPath,
"Uploads", parsedContentDisposition.FileName.Trim('"'));
using (var stream = System.IO.File.OpenWrite(filename))
{
await file.CopyToAsync(stream);
}
//Save to the Database
var newPartner = Mapper.Map<Partners>(thePartner);
_repository.AddPartner(newPartner);
if(await _repository.SaveChangesAsync())
{
return Created($"api/partners/{thePartner.Name}", Mapper.Map<PartnersViewModel>(newPartner));
}
else
{
return BadRequest("Failed to save to the database");
}
}
return BadRequest(ModelState);
}
ViewModel:
public class PartnersViewModel
{
[Required]
public string Name { get; set; }
public string Href { get; set; }
public IFormFile file { get; set; }
}
Angular post method:
vm.addPartner = function () {
vm.isBusy = true;
vm.errorMessage = "";
$http.post("/api/partners", vm.newPartner)
.then(function (response) {
//success
console.log(response);
vm.partners.push(response.data);
vm.newPartner = {};
}, function () {
//failure
vm.errorMessage = "Failed to add new Partner";
})
.finally(function () {
vm.isBusy = false;
});
};
HTML form:
<div class="col-md-6 col-md-offset-3">
<div class="text-danger" ng-show="vm.errorMessage">{{ vm.errorMessage }}</div>
<wait-cursor ng-show="vm.isBusy"></wait-cursor>
<form novalidate name="newPartnerForm" enctype="multipart/form-data" ng-submit="vm.addPartner()">
<div class="form-group">
<label for="name">Nazwa Partnera</label>
<input class="form-control" type="text" id="name" name="name" ng-model="vm.newPartner.name" required/>
<span ng-show="newPartnerForm.name.$error.required" class="text-warning">To pole jest wymagane</span>
</div>
<div class="form-group">
<label for="file">Ścieżka</label>
<input type="file" id="uploader" name="file" class="btn btn-primary" accept="image/*" ng-model="vm.newPartner.file" ngf-multiple="false">
</div>
<div class="form-group">
<label for="href">Link do strony partnera</label>
<input class="form-control" type="text" id="href" name="href" ng-model="vm.newPartner.href"/>
</div>
<div class="form-group">
<input type="submit" value="Add"
class="btn btn-success btn-sm"
ng-disabled="newPartnerForm.$invalid" />
</div>
</form>

Categories