Creating objects from IDataReader - c#

I have created the following to create User objects with an ObservableCollection of UserModule objects called UserModules.
I have approx. 100000 user records, each user could have up to 10 module records and this is taking minutes to finish.
This may mean changing from IDataReader, open to suggestion. Can someone suggest a more efficient way to do this?
public void LoadUsers()
{
clsDAL.SQLDBAccess db = new clsDAL.SQLDBAccess("USERS");
clsDAL.SQLDBAccess db_user_modules = new clsDAL.SQLDBAccess("USERS");
try
{
db.setCommandText(#"SELECT * FROM Users");
using (var reader = db.ExecuteReader())
{
while (reader.Read())
{
var user = new User();
MapUser(reader, user);
_users.Add(user);
db_user_modules.setCommandText(#"SELECT MODULE_ID, USER_MODULE_ACCESS FROM USER_MODULE_SECURITY Where USER_ID = " + user.User_ID);
using (var reader_user_modules = db_user_modules.ExecuteReader())
{
while (reader_user_modules.Read())
{
MapUserModule(reader_user_modules, user);
}
}
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
finally
{
db = null;
}
}
MapUser
public static void MapUser(IDataRecord record, User user)
{
try
{
user.User_ID = NullSafeGetter.GetValueOrDefault<int>(record, "USER_ID");
user.Username = NullSafeGetter.GetValueOrDefault<string>(record, "USERNAME");
user.Name = NullSafeGetter.GetValueOrDefault<string>(record, "NAME");
user.Job_Title = NullSafeGetter.GetValueOrDefault<string>(record, "JOB_TITLE");
user.Department = NullSafeGetter.GetValueOrDefault<string>(record, "DEPARTMENT");
user.Company = NullSafeGetter.GetValueOrDefault<string>(record, "COMPANY");
user.Phone_Office = NullSafeGetter.GetValueOrDefault<string>(record, "PHONE_OFFICE");
user.Phone_Mobile = NullSafeGetter.GetValueOrDefault<string>(record, "PHONE_MOBILE");
user.Email = NullSafeGetter.GetValueOrDefault<string>(record, "EMAIL");
user.Password = NullSafeGetter.GetValueOrDefault<string>(record, "PASSWORD");
user.Last_Login = NullSafeGetter.GetValueOrDefault<DateTime>(record, "LAST_LOGIN");
user.Status = NullSafeGetter.GetValueOrDefault<int>(record, "STATUS");
user.Session_Timeout = NullSafeGetter.GetValueOrDefault<int>(record, "SESSION_TIMEOUT");
}
catch (Exception ex)
{
MessageBox.Show("Mapping User error: " + ex.Message);
throw;
}
}
MapUserModule
private static void MapUserModule(IDataRecord record, User user)
{
try
{
int m_id = NullSafeGetter.GetValueOrDefault<int>(record, "MODULE_ID");
int uma = NullSafeGetter.GetValueOrDefault<int>(record, "USER_MODULE_ACCESS");
user.UserModules.Add(new Users.UserModule(user.User_ID, m_id, uma));
}
catch (Exception ex)
{
throw new Exception("Mapping UserModule error:\n" + ex.Message);
}
}

public IEnumerable<UserModule> GetUserModules()
{
using(var db = ....)
db.setCommandText("SELECT * FROM USERMODULES");
using (var reader = db.ExecuteReader())
{
while (reader.Read())
{
var userId = reader[...];
var m_id = reader[...];
var uma = reader[...];
yield return new UserModule (userid, m_id, uma)
}
}
}
public IEnumerable<User> GetUsers()
{
var userModulesLookup = GetUserModules().ToLookup(x => x.UserId);
using (var db = ...)
{
db.setCommandText("SELECT * FROM USERS");
using (var reader = db.ExecuteReader())
{
while (reader.Read())
{
var userId = reader["userId"];
...blah blah blah...
var user = return new User();
user.Modules = new ObservableCollection<UserModule>
(userModulesLookup[userId]);
...blah blah blah...
yield return user;
}
}
}
}
public void LoadUsers()
{
var users = GetUsers();
foreach(var u in users)
_users.Add(u);
}

As far as I know, there is no faster solution than using a DataReader.
I would recommend you profile the code to see what is taking up most of the time. IIRC, adding a large number of items to an observable collection one at a time is slow. Try adding them to a List<> temporarily to try and isolate the problem.

Related

Bug in order program in which payment can be bypassed

This project makes the customer first create an order and them has to pay for said order via Braintree, However the issue that I am getting is that a customer can create an order and them close the application. This will cause the order to still exist however the customer did not have to pay for their order. If any one knows of a work around for this their help would be thanked. (The orders and payments work. Its just this bug that I'm worried about)
Orders Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> FirstClassCreate(FormCollection values)
{
var order = new Order();
TryUpdateModel(order);
var customer = db.Users.FirstOrDefault(x => x.Email == User.Identity.Name);
var cart = ShoppingCart.GetCart(this.HttpContext);
try
{
Sets the order attributes
order.DeliveryDate = DateTime.Now.AddDays(1);
order.DeliveryMethod = "First Class";
order.FirstName = customer.FirstName;
order.LastName = customer.LastName;
order.PostalCode = customer.PostalCode;
order.State = customer.State;
order.City = customer.City;
order.Email = customer.Email;
order.Country = customer.Country;
order.Phone = customer.PhoneNumber;
order.Address = customer.Address;
order.Username = customer.Email;
order.OrderDate = DateTime.Now;
var currentUserId = User.Identity.GetUserId();
order.Total = cart.GetFirstClass();
if (order.SaveInfo && !order.Username.Equals("guest#guest.com"))
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
var ctx = store.Context;
var currentUser = manager.FindById(User.Identity.GetUserId());
//Save this back
//http://stackoverflow.com/questions/20444022/updating-user-data-asp-net-identity
//var result = await UserManager.UpdateAsync(currentUser);
await ctx.SaveChangesAsync();
await storeDB.SaveChangesAsync();
}
Saves the order to the database
//Save Order
storeDB.Orders.Add(order);
await storeDB.SaveChangesAsync();
//Process the order
cart = ShoppingCart.GetCart(this.HttpContext);
order.Total = cart.GetFirstClass();
order = cart.CreateOrder(order);
return RedirectToAction("FirstClass", "Checkouts");
}
catch
{
//Invalid - redisplay with errors
return View(order);
}
}
Checkouts controller
public ActionResult CreateFirstClass(FormCollection collection)
{
var gateway = config.GetGateway();
Decimal amount;
//Need to get the amount
try
{
amount = Convert.ToDecimal(Request["amount"]);
}
catch (FormatException e)
{
TempData["Flash"] = "Error: 81503: Amount is an invalid format.";
return RedirectToAction("New");
}
string nonceFromTheClient = collection["payment_method_nonce"];
var cart = ShoppingCart.GetCart(this.HttpContext);
//if (id == null)
//{
// return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
//}
//order = Orders.FindAsync(id);
Gets the necessary payment methods
var request = new TransactionRequest
{
Amount = cart.GetFirstClass(),
PaymentMethodNonce = nonceFromTheClient,
Options = new TransactionOptionsRequest
{
SubmitForSettlement = true
}
};
cart.EmptyCart();
Result<Transaction> result = gateway.Transaction.Sale(request);
if (result.IsSuccess())
{
Transaction transaction = result.Target;
return RedirectToAction("Show", new { id = transaction.Id });
}
else if (result.Transaction != null)
{
return RedirectToAction("Show", new { id = result.Transaction.Id });
}
else
{
string errorMessages = "";
foreach (ValidationError error in result.Errors.DeepAll())
{
errorMessages += "Error: " + (int)error.Code + " - " + error.Message + "\n";
}
TempData["Flash"] = errorMessages;
return RedirectToAction("New");
}
}
#

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();
}
}

Access Modifiers - Should be loaded only once

Can We prevent the following from loading more than once in my application. ie any other alternative than this?
public IEnumerable<User> users()
{
var users = Userlist();
return users.ToList();
}
public static List<User> Userlist()
{
string strSQL = "";
List<User> users = new List<User>();
strSQL = "select USERID,USERNAME,PASSWORD from USERS";
//if (Userlist().Count > 0)
//{
// return Userlist();
//}
//else
//{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString))
{
using (var command = new SqlCommand(strSQL, connection))
{
connection.Open();
using (var dataReader = command.ExecuteReader())
{
while (dataReader.Read())
{
users.Add(new User { Id = Convert.ToInt32(dataReader["USERID"]), user = dataReader["USERNAME"].ToString(), password = Decrypt(dataReader["PASSWORD"].ToString()), estatus = true, RememberMe = true });
}
}
}
}
return users;
// }
}
I just wanted the solution to be like the commented part(which does not work here).
EDIT : I just wanted to avoid unnecessary database calls.
Thanks in Advance!
The usual trick is to lazily load them. You could just use a Lazy<T>, but a double-checked simple field works too:
static List<Foo> fetched;
static readonly object syncLock = new object(); // because: threading
public static List<Foo> Whatever {
get {
var tmp = fetched;
if(tmp != null) return tmp;
lock(syncLock) {
tmp = fetched;
if(tmp != null) return tmp; // double-checked lock
return fetched = GetTheActualData();
}
}
}
private static List<Foo> GetTheActualData() {...}
Additional thoughts:
storing passwords is never a good idea
List<T> is mutable; you should make sure people can't change the list or the items in the list if you are storing it statically
what do you do when the data changes at the database? how does it update?
You can also use caching for this.
The idea is that, the List<Users> will be cached, and any time when applications asks for the user list, we return it from the cache, and avoiding the database hit thereof.
A sample implementation could be something like this. Suggest to read more about caching, as there are many aspects that needs to taken care like, when the cache will expire, how it will get invalidate if new users are entered in database etc.
public List<User> Userlist()
{
ObjectCache cache = MemoryCache.Default;
var users = cache["users"];
if (users == null)
{
CacheItemPolicy policy = new CacheItemPolicy();
//For dmonstration, I used cache expring after 1 day
//Set the cache policy as per your need
policy.AbsoluteExpiration = DateTime.Now.AddDays(1);
// Fetch the users here from database
List<User> userList = GetUsersFromDatabase();
//Set the users in the cache
cache.Set("users", userList, policy);
}
return cache["users"] as List<User>;
}
private static List<User> GetUsersFromDatabase()
{
string strSQL = "";
List<User> users = new List<User>();
strSQL = "select USERID,USERNAME,PASSWORD from USERS";
//if (Userlist().Count > 0)
//{
// return Userlist();
//}
//else
//{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString))
{
using (var command = new SqlCommand(strSQL, connection))
{
connection.Open();
using (var dataReader = command.ExecuteReader())
{
while (dataReader.Read())
{
users.Add(new User { Id = Convert.ToInt32(dataReader["USERID"]), user = dataReader["USERNAME"].ToString(), password = Decrypt(dataReader["PASSWORD"].ToString()), estatus = true, RememberMe = true });
}
}
}
}
return users;
}
Use Lazy, it is thread safe. Lazy
private Lazy<IEnumerable<User>> users = new Lazy<IEnumerable<User>>(Userlist);
public Lazy<IEnumerable<User>> Users
{
get
{
return this.users;
}
}
public static IEnumerable<User> Userlist()
{
string strSQL = "";
List<User> users = new List<User>();
strSQL = "select USERID,USERNAME,PASSWORD from USERS";
//if (Userlist().Count > 0)
//{
// return Userlist();
//}
//else
//{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString))
{
using (var command = new SqlCommand(strSQL, connection))
{
connection.Open();
using (var dataReader = command.ExecuteReader())
{
while (dataReader.Read())
{
users.Add(new User { Id = Convert.ToInt32(dataReader["USERID"]), user = dataReader["USERNAME"].ToString(), password = Decrypt(dataReader["PASSWORD"].ToString()), estatus = true, RememberMe = true });
}
}
}
}
return users;
// }
}

DistinguishedName attribute of Active Directory

This is my code :
public bool ActiveDirectoryAuthenticate(string username, string password)
{
var result = false;
using (var entry = new DirectoryEntry("LDAP://*****/DC=******,DC=biz",username,password,AuthenticationTypes.Secure))
{
var searcher = new DirectorySearcher(entry){Filter = "objectClass=user"};
try
{
var sr = searcher.FindOne();
var PathDic = sr.Properties["distinguishedName"][0].ToString();
result = true;
}
catch (Exception exception)
{
}
}
return result;
}
The problem is
sr.Properties["distinguishedName"][0].ToString();
does not return correct value.
Please help me
Just an idea but don't you need to put value like this :
var PathDic = sr.Properties["distinguishedName"][0].Value.ToString();
My problem resolve:
public bool ActiveDirectoryAuthenticate(string username, string password)
{
var result = false;
using (
var entry = new DirectoryEntry("LDAP://PT/DC=pt,DC=biz", username, password,
AuthenticationTypes.Secure))
{
var searcher = new DirectorySearcher(entry) {Filter = "sAMAccountName=Bank.Members"};
searcher.PropertiesToLoad.Add("distinguishedName");
try
{
var sr = searcher.FindOne();
var name = sr.Properties["distinguishedName"][0].ToString();
result = true;
}
catch (Exception exception)
{
}
}
return result;
}

You don't have permission to post in a group

I've finished a program in C# which integrates with Facebook and posts to more than one group in a click
but I am facing a problem right now when there is a group that you don't have a permission to post to I can't complete posting to the rest
here's the post function
I put it in other Class
public static bool PostImage(Frm form,string AccessToken, string Status, string ImagePath)
{
try
{
if (form.listBox2 .SelectedItems .Count > 0)
{
string item;
foreach (int i in form. listBox2.SelectedIndices)
{
item = form.listBox2.Items[i].ToString();
groupid = item;
FacebookClient fbpost = new FacebookClient(AccessToken);
var imgstream = File.OpenRead(ImagePath);
dynamic res = fbpost.Post("/" + groupid + "/photos", new
{
message = Status,
File = new FacebookMediaStream
{
ContentType = "image/jpg",
FileName = Path.GetFileName(ImagePath)
}.SetValue(imgstream)
});
result = true;
}
}
return result;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return false;
}
}
You need to put a try catch block inside the loop. Then, in the catch block you log the error (or do whatever you want with it) then continue the loop:
foreach (int i in form. listBox2.SelectedIndices)
{
try
{
item = form.listBox2.Items[i].ToString();
groupid = item;
FacebookClient fbpost = new FacebookClient(AccessToken);
var imgstream = File.OpenRead(ImagePath);
dynamic res = fbpost.Post("/" + groupid + "/photos", new
{
message = Status,
File = new FacebookMediaStream
{
ContentType = "image/jpg",
FileName = Path.GetFileName(ImagePath)
}.SetValue(imgstream)
});
result = true;
}
catch(exception excp)
{
//Do something with the exception
}
}
Now I don't know exactly how your code works, but this should give you a rough idea.

Categories