I am using ASP.NET Core to upload files to my database.
Where I have two database, one for the create and for the files.
My code looks like this:
public async Task<IActionResult> Create([Bind("ID,Name,Email,Job Title,ICollection<IFormFile> uploads, Track track)
{
if (ModelState.IsValid)
{
_context.Add(track);
// Uploading files for the Request Database
foreach (var upload in uploads)
{
if (upload.Length > 0)
{
// Getting file into buffer.
byte[] buffer = null;
using (var stream = upload.OpenReadStream())
{
buffer = new byte[stream.Length];
stream.Read(buffer, 0, (int)stream.Length);
}
// Converting buffer into base64 code.
string base64FileRepresentation = Convert.ToBase64String(buffer);
// Saving it into database.
_context.Upload.Add(new Request()
{
UploadName = string.Format("{0}_{1}", DateTime.UtcNow.ToString("yyyyMMddHHmmss"), Request.FileName),
Uploadcode = base64FileRepresentation,
TrackID = track.ID,
});
await _context.SaveChangesAsync();
}
}
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(track);
}
In the Edit page, I want to have a button to delete the file that was uploaded to the Track. I have tried to change the delete action from the Controller to the following code, but it didn't work:
[HttpPost, ActionName("DeleteRequest")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteRequest(int id)
{
var x= await _context.Upload.SingleOrDefaultAsync(m => m.UploadID == id);
_context.Upload.Remove(x);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
My view Code
<a asp-action="DeleteRequest"><span class="glyphicon glyphicon-trash" style="color:red;"></span></a>
when I click it, it takes me to empty page with this URL:
localhost:44444/Tracks/DeleteRequest
<a asp-action="DeleteRequest" asp-controller="UpdatYourControllerName"
asp-route-id="#model.UploadId"><span class="glyphicon glyphicon-trash" style="color:red;"></span></a>
public async Task<IActionResult> DeleteRequest(int id)
{
// here debug the id you passed is actually present in db
var x= await _context.Upload.FirstOrDefaultAsync(m => m.UploadID == id);
if(x!=null)
{
_context.Upload.Remove(x);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
}
Related
I have a list where I upload a file for each record and send them all together to the controller. The code works correctly, but if I don't upload a file for one of them and an empty record is sent, an error occurs.
[HttpPost]
public async Task<IActionResult> SabtEditTaxParvanedAsync([FromForm]IEnumerable<TaxParvande> taxParvandes)
{
if (taxParvandes == null)
{
return Content("File not selected");
}
foreach (var item in taxParvandes)
{
var path = Path.Combine(_environment.WebRootPath, "ListUpload", item.prosessMastand.FileName);
using (FileStream stream = new FileStream(path, FileMode.Create))
{
await item.prosessMastand.CopyToAsync(stream);
stream.Close();
}
var taxDomainModel = new TaxDomainModel
{
prosessId =item.prosessId,
prosessName = item.prosessName,
state = item.state,
FilePath = path,
};
_context.Add(taxDomainModel);
await _context.SaveChangesAsync();
}
return View();
}
But if I don't upload a file for one of them and an empty record is
sent, an error occurs.
Well, in this scenario, you might encounter null reference exception. To overcome this error you could set item.prosessMastand == null then to continue loop which will skip the error upon empty insertion.
public async Task<IActionResult> SabtEditTaxParvanedAsync([FromForm] IEnumerable<TaxParvande> taxParvandes)
{
if (taxParvandes == null)
{
return Content("File not selected");
}
foreach (var item in taxParvandes)
{
if (item.prosessMastand == null)
{
continue;
}
var path = Path.Combine(_environment.WebRootPath, "ListUpload", item.prosessMastand.FileName);
using (FileStream stream = new FileStream(path, FileMode.Create))
{
await item.prosessMastand.CopyToAsync(stream);
stream.Close();
}
var taxDomainModel = new TaxDomainModel
{
prosessName = item.prosessName,
state = item.state,
filePath = path,
};
_context.Add(taxDomainModel);
await _context.SaveChangesAsync();
}
return RedirectToAction("Index");
}
Output:
In asp.net core 6 and CSOM library, I'm trying add a permission to a SPO file as following code.
public async Task<IActionResult> AddPermission(Guid guid, String[] emailList)
{
using (var authenticationManager = new AuthenticationManager())
using (var context = authenticationManager.GetContext(_site, _user, _securePwd))
{
File file= context.Web.GetFileById(guid);
SetFilePermission(context, file, emailList);
file.ListItemAllFields.SystemUpdate();
context.Load(file.ListItemAllFields);
await context.ExecuteQueryAsync();
return NoContent();
}
}
private static void SetFilePermission(ClientContext context, File file, string[] emailList)
{
if (emailList != null)
{
file.ListItemAllFields.BreakRoleInheritance(true, false);
var role = new RoleDefinitionBindingCollection(context);
role.Add(context.Web.RoleDefinitions.GetByType(permissionLevel));
foreach (string email in emailList)
{
User user = context.Web.SiteUsers.GetByEmail(email);
file.ListItemAllFields.RoleAssignments.Add(user, role);
}
}
}
This work successfully if only the user is available in SPO, or exception occurs. To avoid non-available user exception, I tried to move Load() and ExecuteQuery() to SetFilePermission method.
public async Task<IActionResult> AddPermission(Guid guid, String[] emailList)
{
using (var authenticationManager = new AuthenticationManager())
using (var context = authenticationManager.GetContext(_site, _user, _securePwd))
{
File file= context.Web.GetFileById(guid);
SetFilePermission(context, file, emailList);
// file.ListItemAllFields.SystemUpdate();
// context.Load(file.ListItemAllFields);
// await context.ExecuteQueryAsync();
return NoContent();
}
}
private static void SetFilePermission(ClientContext context, File file, string[] emailList)
{
if (emailList != null)
{
file.ListItemAllFields.BreakRoleInheritance(true, false);
var role = new RoleDefinitionBindingCollection(context);
role.Add(context.Web.RoleDefinitions.GetByType(permissionLevel));
foreach (string email in emailList)
{
User user = context.Web.SiteUsers.GetByEmail(email);
file.ListItemAllFields.RoleAssignments.Add(user, role);
// Move load and executequery method to here.
file.ListItemAllFields.SystemUpdate();
context.Load(file.ListItemAllFields);
context.ExecuteQueryAsync();
}
}
}
Suddenly, exception disappear even though the user is not available in SPO!
But other available emails in emailList also fail to add permission, just result in return NoContent eventually. Does anyone know the myth behind the process and explain it to me?
I am new to Razor page but have been working in aspx. This below is my code - please help me convert this to a Razor page:
void Page_Load(object sender, EventArgs e)
{
foreach(string f in Request.Files.AllKeys)
{
HttpPostedFile file = Request.Files[f];
file.SaveAs("C:\\e_data\\WorkPage\\IMS18\\ALBAB_Dynamic\\20008\\Case_Manager\\" + file.FileName);
}
}
I want to change to razor page code.
Here's what I use for uploading a single file and storing the path to the file in a database. It'll explain the bits that Microsoft left out of it's docs (for instance the path to the base directory in .netcore2.2) Note that security is not much of a concern for me as this is a small company intranet... but there's bits in there about getting filename without extension, and you may want to store without the file extension for security reasons (or remove and then add your own extension):
public async Task<IActionResult> OnPostAsync()
{
if (id == null)
{
return NotFound();
}
Kit = await _context.Kits.FirstOrDefaultAsync(m => m.ID == id);
if (Kit == null)
{
return NotFound();
}
if (Request.Form.Files.Count > 0)
{
IFormFile file = Request.Form.Files[0];
string folderName = "UploadedOriginalBOMs";
string OrgBOMRootPath = Path.Combine(AppContext.BaseDirectory, folderName);
if (!Directory.Exists(OrgBOMRootPath))
{
Directory.CreateDirectory(OrgBOMRootPath);
}
string sFileExtension = Path.GetExtension(file.FileName).ToLower();
string fullPath = Path.Combine(OrgBOMRootPath, file.FileName);
// StringBuilder sb = new StringBuilder();
if (file.Length > 0)
{
String cleanFilename = Path.GetFileNameWithoutExtension(file.FileName);
using (var stream = new FileStream(fullPath, FileMode.Create))
{
file.CopyTo(stream);
}
Kit.PathToOriginalBOM = "UploadedOriginalBOMs/" + file.FileName;
_context.Kits.Attach(Kit).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
}
else
{
if (!ModelState.IsValid)
{
return Page();
}
}
return RedirectToPage("./Index");
}
You'll notice that you can just use the same forloop as in your .aspx file.
When the line db.savechanges() hits the breakpoint. Nothing happens. no errors in the catch block. The browser just freezes and data is not saved. I am using oracle with asp.net mvc. my code is given below;
public ResponseResult AddUserPermission(USER_PERMISSION permission)
{
try
{
_db.Entry(permission).State = EntityState.Modified;
_db.SaveChanges();
return new ResponseResult();
}
catch (Exception ex)
{
//return new ResponseResult();
return new ResponseResult(ResutlType.Error, ex.Message);
}
}
And the controller calls the method is given below:
[HttpPost]
[CustomAuthorize("Admin")]
public ActionResult Create(USER model)
{
try
{
string moduleId = Request.Form["ModuleId"];
string isSelected = Request.Form["IsSelected"];
model.DATE_CREATED = DateTime.Now;
model.DATE_UPDATED = DateTime.Now;
model.STATUS = (int)Status.Active;
var userPermission = processPermissionData(moduleId, isSelected);
//userPermission contains a list of permissions which i am trying to save
_userService.Add(model);
foreach (var permission in userPermission)
{
_userService.AddUserPermission(permission);
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I get no response from the browser or VS 15. All i get is the loading sign in the browser tab.
I'm following this article to delete a user in Identity 2.0
http://www.asp.net/mvc/tutorials/mvc-5/introduction/examining-the-details-and-delete-methods
However, I need to delete all related records in AspNetUserRoles first and then delete the user.
I found an example which is written in Identity 1.0 and some of methods used inside this example don't exist.
// POST: /Users/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(string id)
{
if (ModelState.IsValid)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var user = await context.Users.FindAsync(id);
var logins = user.Logins;
foreach (var login in logins)
{
context.UserLogins.Remove(login);
}
var rolesForUser = await IdentityManager.Roles.GetRolesForUserAsync(id, CancellationToken.None);
if (rolesForUser.Count() > 0)
{
foreach (var item in rolesForUser)
{
var result = await IdentityManager.Roles.RemoveUserFromRoleAsync(user.Id, item.Id, CancellationToken.None);
}
}
context.Users.Remove(user);
await context.SaveChangesAsync();
return RedirectToAction("Index");
}
else
{
return View();
}
}
I cannot find IdentityManager from anywhere, and context.Users doesn't have FindAsync() method either.
How can I properly delete a User and its related records in Identity 2.0?
I think the classes you're looking for are the UserManager and the RoleManager. In my opinion they are the better way instead of going against the context directly.
The UserManager defines a method RemoveFromRoleAsync which gives you the ability to remove the user (identified by his key) from a given role. It also defines several Find methods, such as FindAsync, FindByIdAsync, FindByNameAsync, or FindByEmailAsync. They all can be used to retrieve a user. To delete a user you should use the DeleteAsync method which accepts a user object as a parameter. To get the roles a user is member of Identity gives you the GetRolesAsync method where you pass in the ID of the user. Also I see that you're trying to remove a login from a user. For this purpose you should use the RemoveLoginAsync method.
All in all your code would look similar to the following one:
// POST: /Users/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(string id)
{
if (ModelState.IsValid)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var user = await _userManager.FindByIdAsync(id);
var logins = user.Logins;
var rolesForUser = await _userManager.GetRolesAsync(id);
using (var transaction = context.Database.BeginTransaction())
{
foreach (var login in logins.ToList())
{
await _userManager.RemoveLoginAsync(login.UserId, new UserLoginInfo(login.LoginProvider, login.ProviderKey));
}
if (rolesForUser.Count() > 0)
{
foreach (var item in rolesForUser.ToList())
{
// item should be the name of the role
var result = await _userManager.RemoveFromRoleAsync(user.Id, item);
}
}
await _userManager.DeleteAsync(user);
transaction.Commit();
}
return RedirectToAction("Index");
}
else
{
return View();
}
}
You'll need to adjust this snippet to your needs, because I don't have an idea how your IdentityUser implementation looks like. Remember to declare the UserManager as needed. An example how you could do this can be found when you create a new project in Visual Studio using Individual Accounts.
Update for ASP.NET Core 2.0 - hope this saves someone a bit of time
ApplicationDbContext context,
UserManager<ApplicationUser> userManager,
ApplicationUser user
var logins = await userManager.GetLoginsAsync(user);
var rolesForUser = await userManager.GetRolesAsync(user);
using (var transaction = context.Database.BeginTransaction())
{
IdentityResult result = IdentityResult.Success;
foreach (var login in logins)
{
result = await userManager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey);
if (result != IdentityResult.Success)
break;
}
if (result == IdentityResult.Success)
{
foreach (var item in rolesForUser)
{
result = await userManager.RemoveFromRoleAsync(user, item);
if (result != IdentityResult.Success)
break;
}
}
if (result == IdentityResult.Success)
{
result = await userManager.DeleteAsync(user);
if (result == IdentityResult.Success)
transaction.Commit(); //only commit if user and all his logins/roles have been deleted
}
}
Brad's point about requiring #Html.AntiForgeryToken() in views is not necessary if you are using latest versions of ASP.NET - see AntiForgeryToken still required
Why not create a SQL trigger for AspNetUsers so deleting a user also deletes the corresponding records for user from AspNetUserRoles and AspNetUserLogins?
I need to invoke DeleteUser from a number of places so I added a static method to AccountController (see below). I'm still learning about MVC, so should be grateful for comments, in particular 1) use of IdentityResult as a return code 2) wisdom of extending AccountController in this way 3) approach for putting password (cleartext) into the Model to validate the action (see sample invocation).
public static async Task<IdentityResult> DeleteUserAccount(UserManager<ApplicationUser> userManager,
string userEmail, ApplicationDbContext context)
{
IdentityResult rc = new IdentityResult();
if ((userManager != null) && (userEmail != null) && (context != null) )
{
var user = await userManager.FindByEmailAsync(userEmail);
var logins = user.Logins;
var rolesForUser = await userManager.GetRolesAsync(user);
using (var transaction = context.Database.BeginTransaction())
{
foreach (var login in logins.ToList())
{
await userManager.RemoveLoginAsync(user, login.LoginProvider, login.ProviderKey);
}
if (rolesForUser.Count() > 0)
{
foreach (var item in rolesForUser.ToList())
{
// item should be the name of the role
var result = await userManager.RemoveFromRoleAsync(user, item);
}
}
rc = await userManager.DeleteAsync(user);
transaction.Commit();
}
}
return rc;
}
Sample invocation - form passes the user's password (cleartext) in Model:
// POST: /Manage/DeleteUser
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteUser(DeleteUserViewModel account)
{
var user = await GetCurrentUserAsync();
if ((user != null) && (user.PasswordHash != null) && (account != null) && (account.Password != null))
{
var hasher = new Microsoft.AspNetCore.Identity.PasswordHasher<ApplicationUser>();
if(hasher.VerifyHashedPassword(user,user.PasswordHash, account.Password) != PasswordVerificationResult.Failed)
{
IdentityResult rc = await AccountController.DeleteUserAccount( _userManager, user.Email, _Dbcontext);
if (rc.Succeeded)
{
await _signInManager.SignOutAsync();
_logger.LogInformation(4, "User logged out.");
return RedirectToAction(nameof(HomeController.Index), "Home");
}
}
}
return View(account);
}
I was looking also for the answer but finally this is what work well for me, even its old post but it may help for someone.
// GET: Users/Delete/5
public ActionResult Delete(string id)
{
using (SqlConnection sqlCon = new SqlConnection(connectionString))
{
sqlCon.Open();
string query = "DELETE FROM AspNetUsers WHERE Id = #Id";
SqlCommand sqlCmd = new SqlCommand(query, sqlCon);
sqlCmd.Parameters.AddWithValue("#Id", id);
sqlCmd.ExecuteNonQuery();
}
return RedirectToAction("Index");
}
// POST: Users/Delete/5
[HttpPost]
public ActionResult Delete(string id, FormCollection collection)
{
try
{
// TODO: Add delete logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}