Reading from CSV file with CsvHelper - c#

I managed to write contents from a List to a CSV file. Now I'm trying to read from the created CSV file and show the content in a Console Application. I'm getting a exception which lead me to some possible solutions on the internet. None of them are working for my Console Application. I hope you can help me.
My code from Program.cs which calls the method in FileOperations.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using CsvHelper;
namespace GimpiesConsoleOOcsvListUI
{
class Program
{
static void Main(string[] args)
{
// First line to skip a row and position all users correctly under the right headers
User user0 = new User("", "", "", "");
// Create user default instances
User user1 = new User("Beheer", "beheer#gimpies.nl", "123", "admin");
User user2 = new User("Inkoop", "inkoop#gimpies.nl", "123", "purchase");
User user3 = new User("Verkoop", "verkoop#gimpies.nl", "123", "sales");
// List of default users (with a list you can add, get and remove items in the list)
List<User> users = new List<User>();
users.Add(user0);
users.Add(user1);
users.Add(user2);
users.Add(user3);
// Create login instance
LoginManager loginMgr = new LoginManager();
// Create stock instance
Stock stock = new Stock();
// Create UserList instance
UserList usrlst = new UserList();
// Call method in UserList.cs
usrlst.Users(users);
Start:
// Welcome message
Console.WriteLine("Welcome to the Gimpies Console Application! Choose 1 to login or 2 to register as guest:");
// Get input from user
string input = Console.ReadLine();
bool successfull = false;
while (!successfull)
{
if(input == "1")
{
Console.WriteLine("Enter your username:");
string username = Console.ReadLine();
Console.WriteLine("Enter your password:");
string password = Console.ReadLine();
foreach (User user in users)
{
if (username == user.UserName && password == user.PassWord && user.UserRole == "admin")
{
// Create Admin instance to be able to call methods in that class
Admin am = new Admin();
// Calling the method in Admin.cs to start Menu logic
am.AdminLoggedIn();
successfull = true;
break;
}
if (username == user.UserName && password == user.PassWord && user.UserRole == "purchase")
{
// Create Purchase instance to be able to call methods in that class
Purchase pc = new Purchase();
// Calling the method in Purchase.cs to start Menu logic
pc.PurchaseLoggedIn();
successfull = true;
break;
}
if (username == user.UserName && password == user.PassWord && user.UserRole == "sales")
{
// Create Sales instance to be able to call methods in that class
Sales sl = new Sales();
// Calling the method in Sales.cs to start Menu logic
sl.SalesLoggedIn();
successfull = true;
break;
}
if (username == user.UserName && password == user.PassWord && user.UserRole == "guest")
{
// Create Guest instance to be able to call methods in that class
Guest gt = new Guest();
// Calling the method in Guest.cs to start Menu logic
gt.GuestLoggedIn();
successfull = true;
break;
}
}
if (!successfull)
{
Console.WriteLine("Your username or password is incorrect, try again !!!");
}
}
else if (input == "2")
{
// Create instance to go to method in class RegisterManager.cs
RegisterManager rm = new RegisterManager();
rm.Register(users);
successfull = true;
goto Start;
}
else if (input == "3")
{
FileOperations fo = new FileOperations();
// Calling the method from FileOperations.cs to write the List here to a CSV file
fo.WriteUsersToCSV(users);
goto Start;
}
else if (input == "4")
{
FileOperations fo = new FileOperations();
// Calling the method from FileOperations.cs to write the List here to a CSV file
fo.ReadUsersFromCSV(users);
goto Start;
}
else
{
Console.WriteLine("Try again !!!");
break;
}
}
// // Loop over stored users within instances inside the list where users are added
// foreach (User user in users)
// {
// if(loginMgr.Login(user))
// {
// // Login successfull
// Console.WriteLine("Login user " + user.UserName);
// }
// else
// {
// // Not successfull
// }
// }
}
}
}
In Program.cs it's about the else if with input == "4".
Then the method ReadUsersFromCSV is called inside FileOperations.cs:
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Globalization;
using System.Linq;
using CsvHelper;
namespace GimpiesConsoleOOcsvListUI
{
// Handles CRUD within CSV files and able to save them
public class FileOperations
{
// Writes to CSV file from List
public void WriteUsersToCSV(List<User> users)
{
// using (var mem = new MemoryStream())
// using (var writer = new StreamWriter(mem))
using (var writer = new StreamWriter("users.csv"))
using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csvWriter.Configuration.Delimiter = ";";
csvWriter.Configuration.HasHeaderRecord = true;
csvWriter.Configuration.AutoMap<User>();
csvWriter.WriteHeader<User>();
csvWriter.WriteRecords(users);
writer.Flush();
// var result = Encoding.UTF8.GetString(mem.ToArray());
// Console.WriteLine(result);
Console.WriteLine("Data saved to users.csv");
}
}
// Reads from CSV file and displays content from it (Work in progress...)
public void ReadUsersFromCSV(List<User> users)
{
// using (var mem = new MemoryStream())
// using (var writer = new StreamWriter(mem))
using (var reader = new StreamReader("users.csv"))
using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture))
{
// csvReader.Configuration.Delimiter = ";";
// csvReader.Configuration.HasHeaderRecord = true;
// csvReader.Configuration.AutoMap<User>();
// csvReader.ReaderHeader<User>();
// var records = csvReader.GetRecords<dynamic>();
// reader.Flush();
// var result = Encoding.UTF8.GetString(mem.ToArray());
csvReader.Read();
csvReader.ReadHeader();
csvReader.Configuration.HeaderValidated = null;
csvReader.Configuration.MissingFieldFound = null;
var records = csvReader.GetRecords<User>();
foreach (var record in records)
{
Console.WriteLine(records);
}
// Console.WriteLine(records);
}
}
// Writes to CSV file from List
public void SaveGimpiesToCSV(List<Gimpies> gimpies)
{
// using (var mem = new MemoryStream())
// using (var writer = new StreamWriter(mem))
using (var writer = new StreamWriter("gimpies.csv"))
using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csvWriter.Configuration.Delimiter = ";";
csvWriter.Configuration.HasHeaderRecord = true;
csvWriter.Configuration.AutoMap<Gimpies>();
csvWriter.WriteHeader<Gimpies>();
csvWriter.WriteRecords(gimpies);
writer.Flush();
// var result = Encoding.UTF8.GetString(mem.ToArray());
// Console.WriteLine(result);
}
}
}
}
The exception:
Unhandled exception. CsvHelper.MissingFieldException: Field with name 'username' does not exist. You can ignore missing fields by setting MissingFieldFound to null.
at CsvHelper.Configuration.ConfigurationFunctions.MissingFieldFound(String[] headerNames, Int32 index, ReadingContext context)
at CsvHelper.CsvReader.GetFieldIndex(String[] names, Int32 index, Boolean isTryGet, Boolean isOptional)
at CsvHelper.CsvReader.GetFieldIndex(String name, Int32 index, Boolean isTryGet)
at CsvHelper.Expressions.ExpressionManager.CreateConstructorArgumentExpressionsForMapping(ClassMap map, List`1 argumentExpressions)
at CsvHelper.Expressions.ObjectRecordCreator.CreateCreateRecordDelegate(Type recordType)
at CsvHelper.Expressions.RecordCreator.GetCreateRecordDelegate(Type recordType)
at CsvHelper.Expressions.RecordCreator.Create[T]()
at CsvHelper.Expressions.RecordManager.Create[T]()
at CsvHelper.CsvReader.GetRecords[T]()+MoveNext()
at GimpiesConsoleOOcsvListUI.FileOperations.ReadUsersFromCSV(List`1 users) in /home/pascalmariany/Projects/Csharp/GimpiesConsoleOOcsvList/GimpiesConsoleOOcsvListUI/FileOperations.cs:line 55
at GimpiesConsoleOOcsvListUI.Program.Main(String[] args) in /home/pascalmariany/Projects/Csharp/GimpiesConsoleOOcsvList/GimpiesConsoleOOcsvListUI/Program.cs:line 132
The contents of the CSV file:
My User.cs:
namespace GimpiesConsoleOOcsvListUI
{
public class User
{
// Constructor
public User(string username, string email, string password, string userrole)
{
_UserName = username;
_Email = email;
_Password = password;
_UserRole = userrole;
}
private string _UserName;
private string _Email;
private string _Password;
private string _UserRole;
public string UserName
{
get { return _UserName; }
set { _UserName = value; }
}
public string Email
{
get { return _Email; }
set { _Email = value; }
}
public string PassWord
{
get { return _Password; }
set { _Password = value; }
}
public string UserRole
{
get { return _UserRole; }
set { _UserRole = value; }
}
}
}
What would I need to change?
Update:
I read all the feedback and I changed some thing in the method within FileOperations.cs:
// Reads from CSV file and displays content from it (Work in progress...)
public void ReadUsersFromCSV(List<User> users)
{
// using (var mem = new MemoryStream())
// using (var writer = new StreamWriter(mem))
using (var reader = new StreamReader("users.csv"))
using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture))
{
try
{
csvReader.Configuration.Delimiter = ";";
csvReader.Configuration.IgnoreBlankLines = true;
csvReader.Configuration.HasHeaderRecord = true;
csvReader.Configuration.PrepareHeaderForMatch = (string header, int index) => header.ToLower();
csvReader.Configuration.MissingFieldFound = null;
// csvReader.Configuration.AutoMap<User>();
// csvReader.ReaderHeader<User>();
// var records = csvReader.GetRecords<dynamic>();
// reader.Flush();
// var result = Encoding.UTF8.GetString(mem.ToArray());
csvReader.Read();
csvReader.ReadHeader();
// csvReader.Configuration.HeaderValidated = null;
// Store all content inside a new List as objetcs
var records = csvReader.GetRecords<User>().ToList();
// users.ForEach(Console.WriteLine);
foreach (var record in records)
{
Console.WriteLine(record);
}
}
catch (CsvHelper.HeaderValidationException exception)
{
Console.WriteLine(exception);
}
}
}
I don't get an exception now, but I get this as output:
GimpiesConsoleOOcsvListUI.User
GimpiesConsoleOOcsvListUI.User
GimpiesConsoleOOcsvListUI.User
GimpiesConsoleOOcsvListUI.User
It's the correct amount of rows, but as you can see it doesn't display the contents which is stored from the CSV file into a List as objects.
Am I missing something?

I managed to solve it. I needed to adjust the foreach loop:
public void ReadUsersFromCSV(List<User> users)
{
// using (var mem = new MemoryStream())
// using (var writer = new StreamWriter(mem))
using (var reader = new StreamReader("users.csv"))
using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture))
{
try
{
csvReader.Configuration.Delimiter = ";";
csvReader.Configuration.IgnoreBlankLines = true;
csvReader.Configuration.HasHeaderRecord = true;
csvReader.Configuration.PrepareHeaderForMatch = (string header, int index) => header.ToLower();
csvReader.Configuration.MissingFieldFound = null;
csvReader.Read();
csvReader.ReadHeader();
// Store all content inside a new List as objetcs
var records = csvReader.GetRecords<User>().ToList();
// Loop through the List and show them in Console
foreach (var record in records)
{
Console.WriteLine($"{record.username } {record.email} {record.password} {record.userrole}");
}
}
catch (CsvHelper.HeaderValidationException exception)
{
Console.WriteLine(exception);
}
}
}
Thanks, but the most I learned from this video: Link for Lists

Related

i need to create a csv file with UTF-8-BOM encoding, i am using .NET (C#)

public async Task<IActionResult> DownloadCSVResults([FromBody] ProfilesSearchOptions searchOptions)
{
var report = await profileManager.GetRep(searchOptions);
if (report == null)
{
return NotFound();
}
var result = Encoding.UTF8.GetPreamble().Concat(report.Body).ToArray();
return File(result, "text/csv", $"UserProfiles.{DateTime.Now:yyyy.MM.dd.HH.mm.ss}.csv");
}
public async Task<Report> GetRep(ProfilesSearchOptions searchOptions)
{
if (searchOptions == null)
{
return null;
}
var searchResult = await SearchProfiles(tenantDomain, false, searchOptions);
if (searchResult == null)
{
return null;
}
var report = GenerateReportRecord("Trainee");
var fileAsBytes = CsvService.GetCSVAsBytesWithHeaders(searchResult.UsersProfiles.Select(m => new UserProfileViewModel
{
Id = m.Id,
FirstNameAr = m.FirstNameAr,
FatherNameAr = m.FatherNameAr,
FamilyNameAr = m.FamilyNameAr,
FullNameAr = m.FullNameAr,
Email = m.Tenants?.Select(t => t.Email).Aggregate((t1, t2) => t1 + ", " + t2),
Deleted = m.Deleted.HasValue && m.Deleted.Value ? "Yes" : "No",
}));
report.Body = fileAsBytes;
report.Status = ReportStatus.Success;
return report;
}
public static byte[] GetCSVAsBytesWithHeaders<T>(IEnumerable<T> data)
{
using (var memory = new MemoryStream())
using (var writer = new StreamWriter(memory, new UTF8Encoding(true)))
using (var csvWriter = new CsvWriter(writer))
{
csvWriter.Configuration.RegisterClassMap<AutoClassMapWithApplyDisplayNameAttribute<T>>();
csvWriter.WriteRecords<T>(data);
writer.Flush();
var result = memory.ToArray();
return result;
}
}
private Report GenerateReportRecord(string reportTitle, string reportName)
{
return new Report
{
Id = Guid.NewGuid().ToString(),
ReportTitle = $"{reportTitle}.{DateTime.Now:yyyy.MM.dd.HH.mm.ss}",
Status = ReportStatus.InProgress
};
}
these are the three main functions that I am using the CSV file is created but with UTF-8 Encoding but as I mentioned, I needed it to be UTF-8-BOM...any help? and thanks in advance...
the problem is in my csv file some charater are displaying like that => " الاسم الاول "

Your Campaign is not ready to send in mailchimp api v3 using C#

I created code to send campaign immediately by consuming mailchimp api v3.0 using C# console. When i tried in free account everything goes well, but when i upgrade my account in premium i got this problem (only add 2 members).
My scenario:
create audience => success
add member subscriber into audience that i created => success
create campaign with specific template => success
send cehcklist in campaign already created => return is_ready false
send campaign => return Your Campaign is not ready to send
When I try to run my console program using console c# consume mailchimp api I got this error:
Type: http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/
Title: Bad Request
Status: 400
Detail: Your Campaign is not ready to send.
instance: 214b85f4-a288-44e7-b890-35925d8601ac
When I checked campaign into mailchimp website portal, I saw a message like this:
To send, you need at least 1 subscriber in your list.
This means that there is no recipients in my campaign, here is detail screenshot:
Please has anyone ever faced this, too? I really appreciate any suggestions.
Is there any way to resolve that issue before sending campaign? Because when I checked mailchimp portal (based on screenshot shown above), I back into campaign list then open my campaign above the problem automatically resolve, this is my confusing one.
Because mailchimp api v3.0 has limitation only 500 members subscriber on one call, finally I created class to partition my list:
//partition list of members more than 500
public static class Extensions
{
public static List<List<T>> SplitPartition<T>(this IEnumerable<T> collection, int size)
{
var chunks = new List<List<T>>();
var count = 0;
var temp = new List<T>();
foreach (var element in collection)
{
if (count++ == size)
{
chunks.Add(temp);
temp = new List<T>();
count = 1;
}
temp.Add(element);
}
chunks.Add(temp);
return chunks;
}
}
this my main code using several scenario to handle single method can call in many way:
public class MailChimpProcessor
{
static MailChimpProcessor()
{
//initialize
ApiHelper.InitializeClient(baseUrl, apiKey);
}
public class MailChimpResponse
{
public string result { get; set; }
public GlobalErrorResponseModel error { get; set; }
}
public static MailChimpResponse MailChimpSendCampaign(SendEmailCampaignModel model)
{
MailChimpResponse mailchimpResult = new MailChimpResponse();
#region PROPERTY OBJECT AUDIENCE
Contact contact = new Contact()
{
company = model.audience_company,
address1 = model.audience_address1,
address2 = model.address2Config,
city = model.audience_city,
state = model.audience_state,
zip = model.audience_zip,
country = model.audience_country,
phone = model.phoneConfig
};
CampaignDefaults campaign = new CampaignDefaults()
{
from_name = model.campaign_from_name,
from_email = model.campaign_reply_to,
subject = model.campaign_subject,
language = "en"
};
AudienceRequestModel audienceModel = new AudienceRequestModel();
audienceModel.name = model.audience_name;
audienceModel.contact = contact;
audienceModel.permission_reminder = permissionReminderConfig;
audienceModel.use_archive_bar = true;
audienceModel.campaign_defaults = campaign;
audienceModel.notify_on_subscribe = "";
audienceModel.notify_on_unsubscribe = "";
audienceModel.email_type_option = true;
#endregion
#region PROPERTY OBJECT MEMBER
List<Member> members = new List<Member>();
//prevent duplicate email_address
var queryMemberList = model.members.GroupBy(x => x.email_address).Select(x => x.First());
foreach (var item in queryMemberList)
{
members.Add(new Member
{
email_address = item.email_address.ToLower(),
status = "subscribed",
status_if_new = "subscribed",
merge_fields = new MergeFields()
{
FNAME = item.merge_fields.FNAME,
LNAME = item.merge_fields.LNAME
}
});
}
bool isUploadContact = false;
int offset = 0;
const int numberPerBatch = 500; // maximum member per execution.
double LoopMax = Math.Ceiling(members.Count / (double)numberPerBatch);
//partition array
var PartitionMembers = members.SplitPartition(numberPerBatch);
#endregion
//create audience using post method
var audienceResult = AudienceProcessor.PostAudienceAsync(audienceModel).Result;
#region PROPERTY OBJECT CAMPAIGN
Recipients recipient = new Recipients()
{
list_id = audienceResult.ResponseModel != null ? audienceResult.ResponseModel.id : "0"
};
Settings setting = new Settings()
{
subject_line = model.campaign_subject,
title = model.campaign_title,
reply_to = model.campaign_reply_to,
from_name = model.campaign_from_name,
template_id = model.campaign_template_id
};
CampaignRequestModel campaignModel = new CampaignRequestModel();
campaignModel.recipients = recipient;
campaignModel.type = "regular";
campaignModel.settings = setting;
#endregion
if (audienceResult.ResponseModel != null)
{
MemberProcessor.MemberResponse memberResult = new MemberProcessor.MemberResponse();
while (offset < LoopMax)
{
MemberRequestModel memberModel = new MemberRequestModel();
memberModel.members = PartitionMembers[offset];//list based on index of array
memberModel.update_existing = true;
//post contact member
memberResult = MemberProcessor.PostContatcAsync(memberModel, audienceResult.ResponseModel.id).Result;
if (memberResult.ResponseModel != null)
{
isUploadContact = true;
}
else
{
isUploadContact = false;
}
offset++; // increment
}
//create campaign
if (isUploadContact)//belum tereksekusi
{
//sleep thread 20 seconds after upload subcriber members
System.Threading.Thread.Sleep(20000);
//create campaign using post method
var campaignResult = CampaignProcessor.PostCampaignAsync(campaignModel).Result;
if (campaignResult.ResponseModel.id != null)
{
#region USING ITERATION TO CHECK CAMPAIGN
CampaignProcessor.CampaignResponseCheckList campaignChecklist = new CampaignProcessor.CampaignResponseCheckList();
bool isReadySend = false;
int check = 0;
while (check <= 10) //maksimum 10 iteration
{
//check campaign using get method
campaignChecklist = CampaignProcessor.GetCheckListCampaign(campaignResult.ResponseModel.id).Result;
if (campaignChecklist.ResponseModel.is_ready == true) //when error model is not null
{
isReadySend = true;
break;
}
else
{
isReadySend = false;
}
System.Threading.Thread.Sleep(1000); // will puase every 1 second
check++;
}
if (isReadySend)
{
//sleep action before send campaign
System.Threading.Thread.Sleep(2000);
//send campaign
var sendCampaignResult = CampaignProcessor.SendCampaignAsync(campaignResult.ResponseModel.id).Result;
if (sendCampaignResult.ErrorModel == null)
mailchimpResult.result = sendCampaignResult.ResponseModel;
else
mailchimpResult.error = sendCampaignResult.ErrorModel; //i got this return indicate that my campaign is not ready
}
else
{
mailchimpResult.error = campaignChecklist.ErrorModel;
mailchimpResult.result = $"failed Check List Campaign / Your Campaign is not ready to send.";
}
#endregion
}
else
{
mailchimpResult.error = campaignResult.ErrorModel;
mailchimpResult.result = "failed create Campaign";
}
}
else
{
mailchimpResult.result = $"failed create contact: {offset}";
mailchimpResult.error = memberResult.ErrorModel;
}
}
else
{
mailchimpResult.error = audienceResult.ErrorModel;
mailchimpResult.result = "failed create Audience";
}
return mailchimpResult;
}
}
Try this code below
System.Threading.Thread.Sleep(40000); //try change this one
//create campaign using post method
var campaignResult = CampaignProcessor.PostCampaignAsync(campaignModel).Result;
if (campaignResult.ResponseModel.id != null)
{
#region USING ITERATION TO CHECK CAMPAIGN
CampaignProcessor.CampaignResponseCheckList campaignChecklist = new CampaignProcessor.CampaignResponseCheckList();
bool isReadySend = false;
int check = 0;
while (true) //just change this condition
{
//check campaign using get method
campaignChecklist = CampaignProcessor.GetCheckListCampaign(campaignResult.ResponseModel.id).Result;
if (campaignChecklist.ResponseModel.is_ready == true) //when error model is not null
{
isReadySend = true;
break;
}
else
{
isReadySend = false;
}
check++;
}
if (isReadySend)
{
//send campaign
var sendCampaignResult = CampaignProcessor.SendCampaignAsync(campaignResult.ResponseModel.id).Result;
if (sendCampaignResult.ErrorModel == null)
mailchimpResult.result = sendCampaignResult.ResponseModel;
else
mailchimpResult.error = sendCampaignResult.ErrorModel; //i got this return indicate that my campaign is not ready
}
else
{
mailchimpResult.error = campaignChecklist.ErrorModel;
mailchimpResult.result = $"failed Check List Campaign / Your Campaign is not ready to send.";
}
#endregion

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!

IFtpHomeDirectoryProvider did not rise

I've realized curom authentication for ftp site basing on https://blogs.msdn.microsoft.com/robert_mcmurray/2011/06/30/how-to-create-an-authentication-provider-for-ftp-7-5-using-blogengine-nets-xml-membership-files/, but IFtpHomeDirectoryProvider.GetUserHomeDirectoryData did not rise
public class FtpEngineNetAuthentication : BaseProvider,
IFtpAuthenticationProvider
, IFtpRoleProvider
, IFtpHomeDirectoryProvider
, IFtpPostprocessProvider
, IFtpLogProvider
{
private readonly string _logfile = Path.Combine(#"c:\test", "logs", "FtpExtension.log");
private string _dbConnectionString;
private string _ftpHomeDirectory;
protected override void Initialize(StringDictionary config)
{
// Retrieve the paths from the configuration dictionary.
_dbConnectionString = config["RextorConnectionString"];
_ftpHomeDirectory = config["ftpHomeDirectory"];
}
bool TryGetUser(string login, out User user)
{
user = null;
try
{
using (var conn = new SqlConnection(_dbConnectionString))
{
var command = new SqlCommand("SELECT UserName, Password, HashAlgorithm, PasswordSalt FROM Orchard_Users_UserPartRecord WHERE UserName = #login", conn);
command.Parameters.AddWithValue("#login", login);
conn.Open();
using (var reader = command.ExecuteReader())
{
if (reader.Read()) // Don't assume we have any rows.
{
user = new User()
{
Login = reader.GetString(0),
Password = reader.GetString(1),
HashAlgorithm = reader.GetString(2),
PasswordSalt = reader.GetString(3)
};
}
}
conn.Close();
}
}
catch (Exception)
{
return false;
}
return true;
}
// Define the GetUserHomeDirectoryData method.
string IFtpHomeDirectoryProvider.GetUserHomeDirectoryData(string sessionId, string siteName, string userName)
{
// Test if the path to the home directory is empty.
if (string.IsNullOrEmpty(_ftpHomeDirectory))
{
// Throw an exception if the path is missing or empty.
throw new ArgumentException(#"Missing ftpHomeDirectory value in configuration.");
}
LogMessage($"directory: {userName}");
var result = $#"{_ftpHomeDirectory}\{userName}";
LogMessage(result);
// Return the path to the home directory.
return result;
}
// Define the AuthenticateUser method.
bool IFtpAuthenticationProvider.AuthenticateUser(string sessionId, string siteName, string userName, string userPassword, out string canonicalUserName)
{
// Define the canonical user name.
canonicalUserName = userName.Replace("#", "").Replace(".", "");
// Validate that the user name and password are not empty.
if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(userPassword))
{
// Return false (authentication failed) if either are empty.
return false;
}
try
{
// Create a user object.
User user = null;
// Test if the user name is in the dictionary of users.
if (TryGetUser(userName, out user))
{
var saltBytes = Convert.FromBase64String(user.PasswordSalt);
// Retrieve a sequence of bytes for the password.
bool isValid;
if (user.HashAlgorithm == "PBKDF2")
{
LogMessage($"user password: {user.Password}");
LogMessage($"user salt: {user.PasswordSalt}");
LogMessage($"user salt&pwd: {Encoding.Unicode.GetString(CombineSaltAndPassword(saltBytes, userPassword))}");
// We can't reuse ComputeHashBase64 as the internally generated salt repeated calls to Crypto.HashPassword() return different results.
isValid = true;
//Crypto.VerifyHashedPassword(user.Password, Encoding.Unicode.GetString(CombineSaltAndPassword(saltBytes, userPassword)));
//PasswordHash.ValidatePassword(user.Password, Encoding.Unicode.GetString(CombineSaltAndPassword(saltBytes, userPassword)));
//BCryptHelper.CheckPassword(user.Password, Encoding.Unicode.GetString(CombineSaltAndPassword(saltBytes, userPassword)));
}
else
{
isValid = SecureStringEquality(user.Password, ComputeHashBase64(user.HashAlgorithm, saltBytes, userPassword));
}
//if (isValid && user.HashAlgorithm != DefaultHashAlgorithm)
//{
// var keepOldConfiguration = _appConfigurationAccessor.GetConfiguration("Orchard.Users.KeepOldPasswordHash");
// if (String.IsNullOrEmpty(keepOldConfiguration) || keepOldConfiguration.Equals("false", StringComparison.OrdinalIgnoreCase))
// {
// user.HashAlgorithm = DefaultHashAlgorithm;
// user.Password = ComputeHashBase64(user.HashAlgorithm, saltBytes, userPassword);
// }
//}
return isValid;
}
}
catch (Exception ex)
{
LogMessage(ex.Message);
// Raise an exception if an error occurs.
throw new ProviderException(ex.Message, ex.InnerException);
}
// Return false (authentication failed) if authentication fails to this point.
return false;
}
bool IFtpRoleProvider.IsUserInRole(string sessionId, string siteName,string userName, string userRole)
{
LogMessage($"check role: {userName} - {userRole}");
return true;
}
public FtpProcessStatus HandlePostprocess(FtpPostprocessParameters postProcessParameters)
{
LogMessage("Running Post Process"); //this message never appears
return FtpProcessStatus.FtpProcessContinue;
}
public void Log(FtpLogEntry logEntry)
{
//LogMessage(logEntry.);
}
private void LogMessage(string logEntry)
{
using (var sw = new StreamWriter(_logfile, true))
{
// Retrieve the current date and time for the log entry.
var dt = DateTime.Now;
sw.WriteLine("{0}\t{1}\tMESSAGE:{2}",
dt.ToShortDateString(),
dt.ToLongTimeString(),
logEntry);
sw.Flush();
}
}

Find all subfolders of the Inbox folder using EWS

I have the following Inbox folder structure:
Inbox
--ABC
----ABC 2
----ABC 3
--XYZ
----XYZ 2
--123
----123 A
----123 B
----123 C
I am using Exchange Web Services and the following code to find the child folders of the Inbox folder:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);
service.AutodiscoverUrl("MyName#MyDomain.com");
Mailbox mb = new Mailbox("MyName#MyDomain.com");
FindFoldersResults findResults = service.FindFolders(
WellKnownFolderName.Inbox,
new FolderView(int.MaxValue));
foreach (Folder folder in findResults.Folders)
{
Console.WriteLine(folder.DisplayName);
}
This partly works because it returns the ABC, XYZ, and 123 folders; unfortunately, it does not return the folders inside each of those folders (ABC 2, ABC 3, XYZ 2, 123 A, 123 B, 123 C).
Also, it is possible that a folder could have more than one level of subfolders inside it.
How can I write this code so that it will return all subfolders regardless of how deeply nested they may be?
You can tell EWS to do a deep traversal when searching the folders. You can do this using the FolderView.Traversal property. Your code would then be changed to something similar to the following:
FindFoldersResults findResults = service.FindFolders(
WellKnownFolderName.Inbox,
new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep });
You can page your requests and get the entire folder hierarchy from the server in just a few calls. The key is the FolderView.Traversal property, as Jacob indicates.
For example, for an Exchange mailbox with ~1,300 folders the code below only makes 2 requests. You can set your page size to whatever you like, as long as you stay at or below the server limit.
FYI: Exchange Online (Office365) caps at a maximum of 1,000 items in a response. I haven't tested, so I can't speak for any similar limits when querying an on-premises Exchange Server.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security;
using Exchange = Microsoft.Exchange.WebServices.Data; // from nuget package "Microsoft.Exchange.WebServices"
namespace FolderViewTraversal
{
class Program
{
public static void Main()
{
Exchange.ExchangeService oService;
Dictionary<string, User> oUsers;
oUsers = new Dictionary<string, User>
{
{ "User1", new User("write.to.me1#my.address.com", "Some-Fancy-Password1") },
{ "User2", new User("write.to.me2#my.address.com", "Some-Fancy-Password2") }
};
foreach (KeyValuePair<string, User> Credential in oUsers)
{
File.Delete(String.Format(LOG_FILE_PATH, Credential.Key));
}
foreach (KeyValuePair<string, User> Credential in oUsers)
{
LogFileName = Credential.Key;
Console.WriteLine("Getting message counts for mailbox [{0}]...", LogFileName);
Console.WriteLine();
oService = Service.ConnectToService(Credential.Value);
GetAllFolders(oService, String.Format(LOG_FILE_PATH, Credential.Key));
Console.Clear();
};
Console.WriteLine();
Console.Write("Press any key to exit...");
Console.ReadKey();
}
private static void GetAllFolders(Exchange.ExchangeService Service, string LogFilePath)
{
Exchange.ExtendedPropertyDefinition oIsHidden = default;
List<Exchange.Folder> oFolders = default;
Exchange.FindFoldersResults oResults = default;
bool lHasMore = false;
Exchange.Folder oChild = default;
Exchange.FolderView oView = default;
short nPageSize = 0;
short nOffSet = 0;
List<string> oPaths = default;
List<string> oPath = default;
oIsHidden = new Exchange.ExtendedPropertyDefinition(0x10f4, Exchange.MapiPropertyType.Boolean);
nPageSize = 1000;
oFolders = new List<Exchange.Folder>();
lHasMore = true;
nOffSet = 0;
while (lHasMore)
{
oView = new Exchange.FolderView(nPageSize, nOffSet, Exchange.OffsetBasePoint.Beginning)
{
PropertySet = new Exchange.PropertySet(Exchange.BasePropertySet.IdOnly)
};
oView.PropertySet.Add(oIsHidden);
oView.PropertySet.Add(Exchange.FolderSchema.ParentFolderId);
oView.PropertySet.Add(Exchange.FolderSchema.DisplayName);
oView.PropertySet.Add(Exchange.FolderSchema.FolderClass);
oView.PropertySet.Add(Exchange.FolderSchema.TotalCount);
oView.Traversal = Exchange.FolderTraversal.Deep;
oResults = Service.FindFolders(Exchange.WellKnownFolderName.MsgFolderRoot, oView);
oFolders.AddRange(oResults.Folders);
lHasMore = oResults.MoreAvailable;
if (lHasMore)
{
nOffSet += nPageSize;
}
}
oFolders.RemoveAll(Folder => (bool)Folder.ExtendedProperties[0].Value == true);
oFolders.RemoveAll(Folder => Folder.FolderClass != "IPF.Note");
oPaths = new List<string>();
oFolders.ForEach(Folder =>
{
oChild = Folder;
oPath = new List<string>();
do
{
oPath.Add(oChild.DisplayName);
oChild = oFolders.SingleOrDefault(Parent => Parent.Id.UniqueId == oChild.ParentFolderId.UniqueId);
} while (oChild != null);
oPath.Reverse();
oPaths.Add(String.Format("{0}{1}{2}", String.Join(DELIMITER, oPath), '\t', Folder.TotalCount));
});
oPaths.RemoveAll(Path => Path.StartsWith("Sync Issues"));
File.WriteAllText(LogFilePath, String.Join(Environment.NewLine, oPaths));
}
private static string LogFileName;
private const string LOG_FILE_PATH = "D:\\Emails\\Remote{0}.txt";
private const string DELIMITER = "\\";
}
internal class Service
{
public static Exchange.ExchangeService ConnectToService(User User)
{
return Service.ConnectToService(User, null);
}
public static Exchange.ExchangeService ConnectToService(User User, Exchange.ITraceListener Listener)
{
Exchange.ExchangeService oService = default;
oService = new Exchange.ExchangeService(Exchange.ExchangeVersion.Exchange2013_SP1)
{
Credentials = new NetworkCredential(User.EmailAddress, User.Password)
};
oService.AutodiscoverUrl(User.EmailAddress, RedirectionUrlValidationCallback);
if (Listener != null)
{
oService.TraceListener = Listener;
oService.TraceEnabled = true;
oService.TraceFlags = Exchange.TraceFlags.All;
}
return oService;
}
private static bool RedirectionUrlValidationCallback(string RedirectionUrl)
{
var _with1 = new Uri(RedirectionUrl);
return _with1.Scheme.ToLower() == "https";
}
}
internal class User
{
public string EmailAddress { get; }
public SecureString Password { get; }
public User(string EmailAddress)
{
this.EmailAddress = EmailAddress;
this.Password = new SecureString();
}
public User(string EmailAddress, string Password)
{
this.EmailAddress = EmailAddress;
this.Password = new SecureString();
foreach(char Chr in Password) { this.Password.AppendChar(Chr); };
this.Password.MakeReadOnly();
}
public static User GetUser()
{
Console.Write("Enter email address: ");
string sEmailAddress = Console.ReadLine();
Console.Write("Enter password: ");
User functionReturnValue = new User(sEmailAddress);
while (true)
{
ConsoleKeyInfo oUserInput = Console.ReadKey(true);
if (oUserInput.Key == ConsoleKey.Enter)
{
break; // TODO: might not be correct. Was : Exit While
}
else if (oUserInput.Key == ConsoleKey.Escape)
{
functionReturnValue.Password.Clear();
}
else if (oUserInput.Key == ConsoleKey.Backspace)
{
if (functionReturnValue.Password.Length != 0)
{
functionReturnValue.Password.RemoveAt(functionReturnValue.Password.Length - 1);
}
}
else
{
functionReturnValue.Password.AppendChar(oUserInput.KeyChar);
Console.Write("*");
}
}
if (functionReturnValue.Password.Length == 0)
{
functionReturnValue = null;
}
else
{
functionReturnValue.Password.MakeReadOnly();
Console.WriteLine();
}
return functionReturnValue;
}
}
internal class TraceListener : Exchange.ITraceListener
{
public void Trace(string TraceType, string TraceMessage)
{
File.AppendAllText(String.Format("{0}.txt", Path.Combine("D:\\Emails\\TraceOutput", Guid.NewGuid().ToString("D"))), TraceMessage);
}
}
}

Categories