C# string format alignment not working - c#

I am working on an ASP.Net core application and would like to align some text in a string.
Somehow I am not able to get this working and am probably missing something very obvious here.
So this is my code (simplified):
public class AdminController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ImportOrganizations(ICollection<IFormFile> files)
{
var count = 0;
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
foreach (var file in files)
{
if (file.Length <= 0) continue;
using (var reader = new StreamReader(file.OpenReadStream()))
{
var csv = new CsvReader(reader);
while (csv.Read())
{
// Fields that need to be filled
string name;
try
{
name = csv.GetField<string>("Name");
}
catch (Exception ex)
{
ModelState.AddModelError("", $"Row {csv.Row, 10}, {ex.Message}");
continue;
}
// Check if name has a value
if (string.IsNullOrWhiteSpace(name))
{
ModelState.AddModelError("", $"Row {csv.Row, 10}, Name is a required field");
continue;
}
if (await _context.Organizations.AnyAsync(o => o.Name == name))
{
ModelState.AddModelError("", $"Row {csv.Row, 3}, Organization {name} already exists");
continue;
}
// Add the new Event
var or = new Organization()
{
Name = name
};
_context.Organizations.Add(or);
}
await SaveContext();
}
}
var model = new ImportViewModel("Import Organizations", nameof(ImportOrganizations), count);
return View("Import", model);
}
}
Now when the import file does not have a value in the name field, I expect something like this in my browser:
Row 20 , Name is a required field
But I keep getting this:
Row 20, Name is a required field
Could someone help me out here?

You need to use negative value for the field width, if you want to pad value on the right side:
$"Row {csv.Row, -10}, {ex.Message}"
See Composite Formatting article for more details.

Thanks to the comment of sgmoore, I was able to resolve it.
It seems this is an issue of html, where it is not possible to use multiple whitespaces in a row.

Related

C# use field 1 value if field 2 empty

I am running through a set of records using a for each loop, and also doing simple checks to ensure that good data is inserted into a database table.
Sometimes the dataset can be missing the LegistarID value, the change I need to do in my code, is to add a check for LegistarItem,
if the value of LegistarID is missing, but the AgendaItem value is not, then assign the value of AgendaItem to LegistarID
if LegistarId is missing, and there is also no AgendaItem value, then return a message to the user, to let them know that these values need to be present in the dataset they are trying to import.
I know it does not sound complex, but I am having a hard time making this change successfully. I need a bit of help if possible, please.
Here is my code as I currently have it:
if (ModelState.IsValid)
{
using (Etities db = new Entities())
{
foreach (var i in meeting)
{
if (i.MeetingID == 0)
{
message = string.Format("This file is missing the Meeting ID value of at least 1 record. \n Verify that the data you are trying to upload meets the criteria, and then try to upload your file again.", i.MeetingID);
return new JsonResult { Data = new { status = status, message = message } };
}
else
{
// development
var compositeKey = db.MeetingAgenda.Find(i.MeetingID, i.AgendaItem);
if (compositeKey == null)
{
// Add new
// development
db.MeetingAgenda.Add(i);
//
}
else
{
// Serves as an update, or addition of a previously imported dataset
db.Entry(compositeKey).CurrentValues.SetValues(i.MeetingID);
db.Entry(compositeKey).State = EntityState.Modified;
}
}
}
db.SaveChanges();
status = true;
}
}
else
{
message = string.Format("Please, verify that the file you are trying to upload is correctly formatted, and that the data it contains, meets the expected criteria, then click the upload button again. \n Thank you!");
return new JsonResult { Data = new { status = status, message = message } };
}
I think that part of the code I need is something like this:
else if (i.LegistarID == 0 and i.AgendaItem != 0)
{
i.LegistarID = i.AgendaItem
}
I just am unsure how in the current code place it.
I would check all rows before returning a result.
if (ModelState.IsValid) {
var errors = new List<string> ();
var rowCounter = 1;
using (Etities db = new Entities ()) {
foreach (var i in meeting) {
if (i.MeetingID == 0) {
// Let the user know this row is bad
errors.Add ($"Row {rowCounter}: This file is missing the Meeting ID. Verify that the data you are trying to upload meets the criteria, and then try to upload your file again.");
}
// Check if LegistarID is missing
if (i.LegistarID == 0) {
// Check if Agenda Item is present
if (i.AgendaItem == 0) {
errors.Add ($"Row {rowCounter}: Meeting has no LegistarID and no Agenda Item. Please check data");
} else {
i.LegistarID = i.AgendaItem
}
}
// development
var compositeKey = db.MeetingAgenda.Find (i.MeetingID, i.AgendaItem);
if (compositeKey == null) {
// Add new
// development
db.MeetingAgenda.Add (i);
//
} else {
// Serves as an update, or addition of a previously imported dataset
db.Entry (compositeKey).CurrentValues.SetValues (i.MeetingID);
db.Entry (compositeKey).State = EntityState.Modified;
}
rowCounter++;
}
// If there are errors do not save and return error message
if (errors.Count > 0) {
return new JsonResult { Data = new { status = false, message = string.Join ("\n", errors) } };
}
db.SaveChanges ();
status = true;
}
} else {
message = string.Format ("Please, verify that the file you are trying to upload is correctly formatted, and that the data it contains, meets the expected criteria, then click the upload button again. \n Thank you!");
return new JsonResult { Data = new { status = status, message = message } };
}
The "if(i.MeetingID == 0)" else is redundant, because you are returning if the condition is met. So to avoid unneeded/confusing nesting I would rewrite the actual code (of the loop only) as:
foreach (var i in meeting)
{
if (i.MeetingID == 0)
{
message = string.Format("This file is missing the Meeting ID value of at least 1 record. \n Verify that the data you are trying to upload meets the criteria, and then try to upload your file again.", i.MeetingID);
return new JsonResult { Data = new { status = status, message = message } };
}
// development
var compositeKey = db.MeetingAgenda.Find(i.MeetingID, i.AgendaItem);
if (compositeKey == null)
{
// Add new
// development
db.MeetingAgenda.Add(i);
//
}
else
{
// Serves as an update, or addition of a previously imported dataset
db.Entry(compositeKey).CurrentValues.SetValues(i.MeetingID);
db.Entry(compositeKey).State = EntityState.Modified;
}
}
Then, I would add the new condition in between the MeetingID = 0 check and the rest of the code, like this:
foreach (var i in meeting)
{
if (i.MeetingID == 0)
{
message = string.Format("This file is missing the Meeting ID value of at least 1 record. \n Verify that the data you are trying to upload meets the criteria, and then try to upload your file again.", i.MeetingID);
return new JsonResult { Data = new { status = status, message = message } };
}
// *** New check on LegistarID and AgendaItem ***
if(i.LegistarID == 0)
{
// Is there a chance to fill LegistarID with AgendaItem?
if(i.AgendaItem != 0)
{
// Yes, fill it and then let the rest of the code flow peacefully.
i.LegistarID = i.AgendaItem
}
else
{
// No way: I must stop the procedure here and warn the user about this.
// return "these values need to be present in the dataset they are trying to import."
}
}
// development
var compositeKey = db.MeetingAgenda.Find(i.MeetingID, i.AgendaItem);
if (compositeKey == null)
{
// Add new
// development
db.MeetingAgenda.Add(i);
//
}
else
{
// Serves as an update, or addition of a previously imported dataset
db.Entry(compositeKey).CurrentValues.SetValues(i.MeetingID);
db.Entry(compositeKey).State = EntityState.Modified;
}
}

ExcelReaderFactory and razor pages validating if is the correct file using excelReader

Can't validate if is the correct file, the code breaks but file passes always.
[BindProperty, Required(ErrorMessage = "Please select a file!"), Attachment]
public IFormFile Upload { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
if (Upload != null && Upload.Length > 0)
{
var myFile = Path.Combine(env.ContentRootPath, folderName, Upload.FileName);
var fileExt = Path.GetExtension(Upload.FileName).Substring(1);
if (!supportedTypes.Contains(fileExt))
{
ModelState.AddModelError(string.Empty,
"Only Excel files are permited");
}
else
{
if (myFile.Length > 0)
{
using (var fileStream = new FileStream(myFile, FileMode.Create))
{
await Upload.CopyToAsync(fileStream);
fileStream.Close();
var stream = System.IO.File.Open(myFile, FileMode.Open, FileAccess.Read);
using (var excelStream = ExcelReaderFactory.CreateReader(stream))
{
AddExcelToDB(excelStream);
}
}
}
}
}
else
{
ModelState.AddModelError(string.Empty,
"Please, you must select a file");
}
return RedirectToPage("/Analises/Index");
}
private void AddExcelToDB(IExcelDataReader excelReader)
{
var excelTable = excelReader.AsDataSet().Tables[0];
for (var i = 1; i < excelTable.Rows.Count; i++)
{
//check if the header = the database
if (!((string)excelTable.Rows[0].ItemArray[0]).Contains("Name")
& !((string)excelTable.Rows[0].ItemArray[1]).Contains("Number")
& !((string)excelTable.Rows[0].ItemArray[3]).Contains("Date"))
{
ModelState.AddModelError("Error",
"Header mismatch, please select correct file");
break;
}
var name= (string)excelTable.Rows[i].ItemArray[0];
var number= (int)excelTable.Rows[i].ItemArray[1];
var notif = (string)excelTable.Rows[i].ItemArray[2];
var date= (DateTime)excelTable.Rows[i].ItemArray[3];
TestTable currentExcel = new TestTable
{
Name= name,
Num= number,
Notif = notif,
Date= date
};
this.db.TestTables.Add(currentExcel);
}
this.db.SaveChanges();
}
If the correct file is posted it is inserted correctly in the database and displayed in the /Analises/Index page.
But if a empty file or a file that does not match is uploaded it breaks (doesn't insert) but still redirects without the error message.
Maybe a fresh pair of eyes can point me in the right direction.
Thanks in advance!

ASP.net Web API File Validation filter attribute

I want to create an attribute which will perform following tasks.
Validate the file type as per the file extension.
Validate the file type as per magic number/signature of file.
Validate the file length/size.
If file is validated then I want to store the file into database as as Base 64 string.
I tried it, but in my solution I have to read file twice first in attribute to check extension, magic number and size and secondly to convert the file stream into base 64 string. But Request.Content is forward only reader so it is throwing error when I tried to read the file again.
Please see the code below
File Validator Filter
public class ValidateFileAttribute : ActionFilterAttribute
{
public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
return Task.Factory.StartNew(async () => {
if (Request.Content.IsMimeMultipartContent())
{
var provider = actionContext.Request.Content.ReadAsMultipartAsync(cancellationToken).Result;
foreach (var content in provider.Contents)
{
//Here logic to check extension, magic number and length.
//If any error occurred then throw exception with HttpStatusCode
var fileName = content.Headers.ContentDisposition == null ? string.Empty : content.Headers.ContentDisposition.FileName;
var fileInBytes = content.ReadAsByteArrayAsync().Result;
var extention = fileName.Substring(fileName.LastIndexOf('.') + 1);
var validExtensions = new List<string>() { "pdf", "doc", "docx" };
if (!validExtensions.Contains(extention, StringComparer.OrdinalIgnoreCase))
{
//Return Exception
}
if (fileInBytes != null && fileInBytes.Any())
{
var magicNumber = BitConverter.ToString(fileInBytes).Substring(0, 11);
var validMagicNumbers = new List<string>() { "25-50-44-46", "D0-CF-11-E0", "50-4B-03-04" };
if (!validMagicNumbers.Contains(magicNumber, StringComparer.OrdinalIgnoreCase))
{
// Return Exception
}
}
if(fileInBytes != null && fileInBytes.Any() && fileInBytes.Length >= 3000000)
{
// Return Exception
}
}
}
}, cancellationToken);
}
}
Upload Action Method
[ValidateFile]
[Route("upload")]
[HttpPost]
public DocumentUploadResponse Upload()
{
if (Request.Content.IsMimeMultipartContent())
{
var provider = Request.Content.ReadAsMultipartAsync().Result;
// Getting error here..
foreach (var content in provider.Contents)
{
//Here logic to convert file stream into base 64 string.
//And store that string into Database.
var fileInBytes = content.ReadAsByteArrayAsync().Result;
var fileToStore = Convert.ToBase64String(fileInBytes);
/// Here goes Database code.....
}
}
}
Your help will be appreciated.

CheckBoxList in a complex view

I have searched here many times but I could not find what I want.
I am developing an application where I have USERS with specific Skills, and I want to relate them to specific project.
So I have the following tables: Users, UserSkills and more
My question is: I am using CRUD in MVC4, and when I open the EDIT view from the UserDetail Controller, in order to edit the user information, I need also to add (in the same Edit view) partial view, or any mechanism, where I list the user skills, using CheckBoxes to help in multi-selecting various skills for this user, and then when pressing "Save" it should store the User and UserSkills information back to the dB (MS-SQL).
I am using this Model:
public class SkillsViewModel
{
public IList<Skill> AvailableSkills { get; set; }
public IList<Skill> SelectedSkills { get; set; }
public SavedSkills SevedSkills { get; set; }
public User Usr { get; set; }
}
SavedSkills are the UserSkills Table, which will be used for the dB
AvailableSkills are the Skills Table
SelectedSkills are the ones that are selected in the Edit view
Keeping in mind that the Edit view also contain an image upload file:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(User Usr, HttpPostedFileBase file)
{
#region//validate file is selected
if (file != null)
{
if (file.ContentLength > (512 * 1000)) // 512 KB
{
ModelState.AddModelError("FileErrorMessage", "File size
must be within 512KB");
}
string[] allowedType = new string
[]"image/png", "image/gif",
"image/jpg", "image/jpeg" };
bool isFileTypeValid = false;
foreach (var i in allowedType)
{
if (file.ContentType == i.ToString())
{
isFileTypeValid = true;
break;
}
}
if (!isFileTypeValid)
{
ModelState.AddModelError
("FileErrorMessage", "Only .png,
.gif and .jpg file allowed");
}
}
#endregion
if (ModelState.IsValid)
{
if (Skk.Skk.Count (x => x.IsSelected) == 0)
{
//return "You have not selected any City";
}
else
{
StringBuilder sb = new StringBuilder();
sb.Append("You selected - ");
foreach (Skill skilll in Skk.Skk)
{
if (skilll.IsSelected)
{
sb.Append(skilll.SkillName + ", ");
}
}
//sb.Remove(sb.ToString().LastIndexOf(","), 1);
//return sb.ToString();
}
//Update User
if (file != null)
{
string savePath = Server.MapPath("~/Pictures");
string fileName = Guid.NewGuid() + Path.GetExtension
(file.FileName);
file.SaveAs(Path.Combine(savePath, fileName));
Usr.ImagePath = fileName;
}
using (dBEntities dc = new dBEntities())
{
var v = dc.Users.Where(a => a.Id.Equals
(Usr.Id)).FirstOrDefault();
if (v != null)
{
v.UserName = Usr.UserName;
v.Email = Usr.Email ;
v.StartDate = Usr.StartDate ;
v.Company = Usr.Company ;
v.Position = Usr.Position;
v.Division = Usr.Division ;
v.Department = Usr.Department ;
v.PM = Usr.PM ;
v.AM = Usr.AM;
v.Permissions = Usr.Permissions;
v.IsActive = Usr.IsActive;
if (file != null)
{
v.ImagePath = Usr.ImagePath ;
}
}
dc.SaveChanges();
}
return RedirectToAction("Index");
}
ViewBag.Department = new SelectList
(db.Departments, "DepID", "DepName", Usr.Department);
ViewBag.Division = new SelectList
(db.Divisions, "DivID", "DivName", Usr.Division);
ViewBag.Position = new SelectList
(db.Positions, "PosID","PosName", Usr.Position);
return View(Usr);
}
I hope I have explained it well, and thank you in advance.
I had same situation with you.
I was used chosen to add user's skills. IMHO, it more user friendly then using checkboxes (you can look chosen in action in linked-in, when you add your skills) when you have more than 20 skills in your database.
Chosen is regular HTML "select" tag with multiple attribute but more beautiful.
I also use Ajax JQuery to post my data to controller.
JQuery POST method also support send form data with attached file.
So you don't need to change your Edit action a lot. What you need is add parameter for selected skills (it's a string which separated by comma).

Error adding multiple records MVC

i'm trying to add multiple textbox values to database it is working on just single textbox row but now working when i'm adding multiple rows of textboxes. i'm sharing what i have done so far.
Action Method:
public async Task<ActionResult> Create(FormCollection values)
{
var customer = new Customer();
var model = new TicketViewModel();
TryUpdateModel(model.TicketDetail);
try
{
foreach (var ticket in model.Tickets)
{
ticket.Date = DateTime.Now;
ticket.ProcessId = DateTime.Now.Ticks.ToString().Substring(12, 6);
ticket.CreationMethod = "Manual";
ticket.isCustomer = User.IsInRole("Customer") ? true : false;
ticket.Total = 0;
ticket.Email = model.TicketDetail.Ticket.Email;
customer.City = "Not Specified";
customer.Country = "Not SPecified";
customer.Image = "~/Images/nopic.jpg";
customer.Password = System.Web.Security.Membership.GeneratePassword(11, 3);
customer.IsActive = true;
customer.CreationMethod = "Manual";
customer.DateAdded = DateTime.Now;
customer.Email = ticket.Email;
customer.FirstMidName = string.IsNullOrEmpty(ticket.FullName) ? "Not Specified" : ticket.FullName;
customer.LastName = "Not Specified";
customer.Salutation = "Not Specified";
customer.UserName = DateTime.Now.Ticks.ToString().Substring(3, 9);
//ticket detail
var abcd = values["abcd"].ToString();
var getID = await db.Parts.Where(c => c.PartNumber == abcd)
.FirstOrDefaultAsync();
model.TicketDetail.GenericOrderId = ticket.GenericOrderId;
model.TicketDetail.PersonID = customer.PersonID;
model.TicketDetail.Status = "New";
model.TicketDetail.PartId = getID.PartId;
model.TicketDetail.Ticket.Date = DateTime.Now;
}
try
{
// db.Tickets.Add(ticket);
db.Customers.Add(customer);
db.TicketDetails.Add(model.TicketDetail);
}
catch (Exception ex)
{
ViewBag.PartId = new SelectList(db.Parts.Take(5), "PartId", "Name");
ModelState.AddModelError("", string.Format(ex.Message + "\n" + ex.InnerException));
return View(model.TicketDetail);
}
// Save all changes
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
catch(Exception ex)
{
ModelState.AddModelError("", String.Format(ex.Message + "\n" + ex.InnerException));
//Invalid - redisplay with errors
return View(model.TicketDetail);
}
}
ViewModel:
public class TicketViewModel
{
public TicketViewModel()
{
TicketDetails = new List<TicketDetail>();
TicketDetail = new TicketDetail();
Ticket = new Ticket();
Tickets = new List<Ticket>();
}
public virtual Ticket Ticket { get; set; }
public virtual IEnumerable<Ticket> Tickets { get; set; }
public virtual TicketDetail TicketDetail { get; set; }
public virtual IEnumerable<TicketDetail> TicketDetails { get; set; }
}
it is also giving error on this "TryUpdateModel(model.TicketDetail);" the error is value cannot be null, please guide me i'm stuck here i have searched internet but couldn't found any appropriate solution. i want to add multiple records
First all properties of your TicketViewModel class have to be instantiated.
To add multiple records (multiple Insert) you could use a StringBuilder and append the insert statements to it. You then have one big query string to be executed on your database.
If using values this is also a valid way:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
And loading the data to be inserted directly from a file is even faster.
Edit
(after down voting for no reason)
Because some people act like they know it all:
SQL injections are indeed a serious problem when dealing with Database access. That's no secret at all. A common technique to prevent the SQL query from being 'highjacked' you simply use the SQLCommand.Parameters property which is used to map each value individually to the statement to separate the query statement from the data (values) this way. It's now impossible to inject or manipulate statements whithout breaking them. And server side validation is standard to obtain maximum security as well as escaping special input characters and avoiding the use of privilegs with no or low restrictions.
This is NOT a wrong answer.

Categories