C# Lazy loading & Ajax - c#

I have a class where some properties are going back to the database, ONLY when they are called. So, let consider the following example:
class User
{
public int UserID { get; internal set; }
public string UserName { get; set; }
public Role[] Roles
{
get
{
if (this.UserID > 0)
return RoleRepository.GetByUserID(this.UserID).ToEntityArray();
else
return RoleRepository.GetByUserName(this.UserName).ToEntityArray();
}
}
}
There is also a Role class, but that's probably not important. The 'Roles' property in the 'User' class is kind of like lazy loading. It is only retrieving the info when that property is accessed. The question is how can I use JQuery to ensure that the lazy loading occurs or is that even possible? Any articles on this concept would also be helpful.
Thanks

I don't see what jQuery has to do with this at all.
Touching that Property will trigger the lazy-load.
If you use JQuery to call some HttpHandler/WebMethod/ActionMethod/etc, as soon as you try to iterate through or access that Property it is going to load that data
Also, rather than having that biz logic in your domain object you could try a delegate approach to keep "how" data is bound to that Property in its proper place
class User
{
public int UserID { get; internal set; }
public string UserName { get; set; }
public delegate Role[] GetRolesDelegate(int userId, string username);
public GetRolesDelegate GetRoles { get; set; }
Role[] _roles;
public Role[] Roles
{
get
{
if (_roles == null)
{
_roles = GetRoles == null
? new Role { }
: GetRoles(UserID, UserName).ToEntityArray();
}
return _roles;
}
}
}
Then you could bind that like so:
User user = new User();
user.GetRoles = RoleRepository.GetRoles;

Like hunter I'm not sure what jQuery has to do with this. To make the Roles property lazy load add a private backing property that stores the value the first time it is accessed from the repository. Then, for subsequent accesses, you can just return that private backing variable, rather than going through the RoleRepository. Something like:
class User
{
public int UserID { get; internal set; }
public string UserName { get; set; }
private Role[] _roles;
public Role[] Roles
{
get
{
if (_roles == null)
{
if (this.UserID > 0)
_roles = RoleRepository.GetByUserID(this.UserID).ToEntityArray();
else
_roles = RoleRepository.GetByUserName(this.UserName).ToEntityArray();
}
return _roles;
}
}
}

Related

Create a class to store classes that use different interfaces

I am working on a project in C# which needs to store information about a user. This information is retrieved from their respective libraries which have their own implementations and interfaces. Currently users can either connect from Twitch or Discord, so they will be represented as either TwitchUser or DiscordUser objects. However, I would like to write a class User that will contain one of the 2 classes which should make it easier for me to refer to them in code.
Here is an example of how TwitchUser and DiscordUser look like:
public class TwitchUser : IChatUser
{
public TwitchUser();
public string Id { get; }
public string UserName { get; }
public string DisplayName { get; }
public string Color { get; }
//and so on...
}
public class DiscordUser : SnowflakeObject, IEquatable<DiscordUser>
{
public virtual string Email { get; internal set; }
public virtual string Username { get; internal set; }
public bool Equals(DiscordUser e);
//and so on...
}
I thought I could create a class which accepts generic types but with my implementation I would have to pass BOTH classes which means one of them would be null. This doesn't feel right to me.
public class User<T,D>
{
public TwitchUser VarA { get; set; }
public DiscordUser VarB { get; set; }
}
What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?
I would then also write code inside my User class to return user IDs etc.
Update
For example, when I request a user ID I would perform a check inside User whether I stored a TwitchUser or DiscordUser, and based on the outcome I would return an attribute which represents the user's ID on that platform.
Update 2
A user may only be represented by one of the two classes. For example, if they used Discord as their platform to login then they will only have a DiscordUser object associated with them. Same applies to Twitch platform and it using TwitchUser object. The reason they are different is because these implementation were written by different people using 2 different libraries, which is why they don't use the same interfaces, or inherit from one common class. So what I am trying to do is retroactively add some sort of an inheritance here. This way, when I want to refer to the user in my code, I don't need to write 2 overloads for a function (where one uses TwitchUser and the other uses DiscordUser). I just want to be able to refer to User and let that class decide for me.
those 2 clases I mentioned cannot be modified [...] I want to be able to access all the necessary attributes stored in DiscordUser and TwitchUser
That sounds like a good fit for the adapter pattern. Define an interface as common denominator:
public interface IUser
{
string Id { get; }
string Username { get; }
}
Note that this interface can only contain properties that both objects share, or you're going to need null checks all over the place.
Then create an adapter for each type you want to wrap:
public class TwitchUserAdapter : IUser
{
private readonly TwitchUser _user;
public TwitchUserAdapter(TwitchUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.UserName;
}
public class DiscordUserAdapter : IUser
{
private readonly DiscordUser _user;
public TwitchUserAdapter(DiscordUser user)
{
_user = user;
}
public string Id => _user.Id;
public string Username => _user.Username;
}
Now you can treat both the same:
var users = new List<IUser>();
users.Add(new TwitchUserAdapter(new TwitchUser { Id = "Tfoo", UserName = "Tbar" }));
users.Add(new DiscordUserAdapter(new DiscordUser { Id = "Dfoo", Username = "Dbar" }));
foreach (var user in users)
{
Console.WriteLine($"Id: {user.Id}, Name: {user.Username}");
}
"What is the correct way of combining 2 classes that have different implementations and don't have interfaces in common between?"
One way to accomplish this might be to create a class that contains all the properties you care about, and then create static methods that return an instance of the class based on the properties of a TwitchUser or a DiscordUser:
public class User
{
// Add just the properties you care about
public string Id { get; private set; }
public string UserName { get; private set; }
public string DisplayName { get; private set; }
public string Color { get; private set; }
public string Email { get; private set; }
// Make the default constructor private so instances of this
// class can only be created from one of our static methods
private User() { }
public static User FromTwitch(TwitchUser twitchUser)
{
return new User
{
Id = twitchUser.Id,
Color = twitchUser.Color,
DisplayName = twitchUser.DisplayName,
UserName = twitchUser.UserName
};
}
public static User FromDiscord(DiscordUser discordUser)
{
return new User
{
Email = discordUser.Email,
UserName = discordUser.Username
};
}
}

C#, Android: Delete Singleton

I am working on a project with a lot of account management going on. Unfortunately, the guy who set all of this up is on vacation and something here needs to be done, but I cant really seem to understand what exactly is going on here ( I am kind of new to this...)
So basically, as far as I understand: When someone logs into our app, a singleton account is created. There are two classes that matter here:
namespace Accounts
{
//Generische und Lazy Singleton-Abstraktion
public abstract class AbstractAccount<T> where T : class
{
// Lazy Instanziierung
private static readonly Lazy<T> _instance = new Lazy<T>(() => CreateSingletonInstance());
public static T Instance
{
get
{
// throw new System.InvalidOperationException("out");
return _instance.Value;
}
}
private static T CreateSingletonInstance()
{
// Konstruktion des Singleton-Objekts
return Activator.CreateInstance(typeof(T), true) as T;
}
}
}
and:
class Account : AbstractAccount<Account>
{
// öffentliche Felder und Methoden
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string Description { get; set; }
public List<string>Friendlist { get; set; }
public Bitmap ProfilePicutre { get; set; }
public int Experience { get; set; }
public int gender { get; set; }
public DateTime lastLogin { get; set; }
public DateTime dateCreated { get; set; }
public string Locality { get; set; }
public string Country { get; set; }
public string CountryCode { get; set; }
public int level { get; set; }
public void SetCurrentAccount(tblUsers user, DateTime lastLogin)
{
this.Username = user.getUsername();
this.Email = user.getEmail();
this.Password = user.getPassword();
this.Description = user.getdescription();
this.Experience = user.getexperience();
this.gender = user.getgender();
this.lastLogin = lastLogin;
this.dateCreated = user.getDateCreated();
this.level = CheckLevel(Experience);
}
}
Now here is the issue: When a user is login off and then creating a new account, he or she would still be set up with the properties of the user he just logged out off.
For instance: If he had 1000 xp points, then loggs off and creates a new account, that account would not start at 0 points but at 1000.
I know that his is pretty much (maybe even impossible) for you to handle from another computer but I really need help right here:
private void logoutClick(object sender, EventArgs e)
{
Context mContext = Android.App.Application.Context;
AppPreferences ap = new AppPreferences(mContext);
ap.deletePreferences();
this.FinishAffinity();
//Remove static variables. Just to be sure!
SaveAccountInfo.bpLandScapePicFull = null;
SaveAccountInfo.bpLandScapePicThumb = null;
SaveAccountInfo.bpProfilePicFull = null;
SaveAccountInfo.bpProfilePicThumb = null;
StartActivity(typeof(Activity_AcctCreationLogin));
Finish();
}
If the user was now to logout, the singleton needs to be completely destroyed and set up anew when a nother account is beeing created. I tried "Account.Instance.Dispose()"
but unfortunately, there was no such method as "dispose" after instance.
Is there any chance you guys could help me out a little? That me tremendous! Thanks so much! :)
You can set the value of your instance to a new one.
Create a method in your Account class that does this one upon logout.
_instance = new Lazy<T>(() => CreateSingletonInstance());
You should youse the Singleton pattern with these 2 methods:
public static T GetInstance
{
get
{
if (_instance == null)
_instance = new Lazy<T>(() => CreateSingletonInstance());
return _instance.Value;
}
}
public static void ReleaseInstance // called on logout
{
_instance = null;
}
also, as DavidG pointed out you should add a protected constructor.
Would it be possible for you to implement the IDisposable interface, then write your own dispose method. You could then use this method to clear the data you want cleared. Hope this helps.

Disallow user to perform an update on a field or member of a class and return 405 Method Not Allowed : HTTP

I am working on an api which serves creating,updating,deleting of user settings for an application. My users are of two types
admin user
common user
I have a field public bool ReadOnly { get; set; } which says whether a common user is allowed to change the setting or not.
Now the question is in which layer i need to validate this and throw the 405 response to the client. Please suggest.
private readonly SettingsRepository _SettingsRepository;
[HttpPut("{userid}/settings/{settingName}")]
public IActionResult Put(string userid, [FromBody]Setting setting)
{
var result = _SettingsRepository.Update(userid, setting);
if (result == true)
{
return Ok(201);
}
else
{
return BadRequest();
}
}
//Updates the existing setting for a user having userid
public bool Update(string userid, Setting setting)
{
bool flag = false;
if (userid == null || setting == null)
{
return flag;
}
var existing = Profiles.profiles.Where(p => p.UserID.ToLower() == userid.ToLower() && p.Settings.Any(s => s.Name.ToLower() == setting.Name.ToLower())).SelectMany(res => res.Settings).ToList();
if (existing.Count() > 0)
{
existing.ForEach(e =>
{
e.Name = setting.Name;
e.Value = setting.Value;
e.Type = setting.Type;
e.Valid = setting.Valid;
e.ReadOnly = setting.ReadOnly;
e.ModifiedOn = DateTime.UtcNow;
e.Encrypted = setting.Encrypted;
e.Enabled = setting.Enabled;
e.CreatedOn = setting.CreatedOn;
e.Description = setting.Description;
});
FileSerDe.SerializeSettings<IList<Profile>>(Profiles.profiles, System.IO.Directory.GetCurrentDirectory() + "\\" + "seed.txt");
flag = true;
}
return flag;
}
//Profile Entity
public class Profile
{
public string UserID { get; set; }
public string UserName { get; set; }
public List<Setting> Settings { get; set; }
}
//Setting Entity
public class Setting
{
public string Name { get; set; }
public object Value { get; set; }
public string Type { get; set; }
public bool Encrypted { get; set; }
public bool ReadOnly { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public bool Valid { get; set; }
public bool Enabled { get; set; }
public string Description { get; set; }
}
It looks business logic is in repository. so you can put security measure in repository. do that first thing in repository & throw exception on failed.
this will centralize your business logic to single place.
405 Method not allowed would be used when the HTTP method (e.g. GET or PUT) is specifically not allowed to be used with a given URL, and would apply to all users. For something which is permissions-within your application and related to a specific user it would be more accurate to a send a 403 Forbidden response.
As for the layers, clearly the API Action method is the only one which can return the actual HTTP error code, but since the information that tells you whether the user has permission is held in the database, you could arrange it so that the data layer tells the API layer what the appropriate response should be, perhaps by throwing an exception or by setting a flag on an output parameter to the database method. This would require you to pass information about the current user to the database layer, though, some people think that's unnecessary overhead, unless it's required anyway to record audit data etc.
The alternative is that you could get the API layer to retrieve the relevant data from the database before attempting to run the Update, and make a decision based on that retrieved data, entirely within the API action method. It's really a design decision that is up to you and what suits your application structure. Either way is possible, and, arguably, valid.

Model validation, database constraints

I'm trying to add some architecture to my projects and enrich my models.
I started with CQS (implementation similar to that one: CQS-Sample) and here's my first problem.
Let's say I have two classes like these below:
public class Network
{
public int Id { get; set; }
public User User { get; set; }
private IQueryFactory _queryFactory { get; set; }
public Network(IQueryFactory queryFactory)
{
_queryFactory = queryFactory;
}
public void AddUser(User user)
{
if(this.User == null && user != null)
{
userHasUniqueEmail(user);
this.User = user;
}
}
private void userHasUniqueEmail(User user)
{
bool isUnique = _queryFactory.ResolveQuery<INewUserUniqueQuery>().Execute(user.Email);
if (!isUnique)
{
throw new ArgumentException("E-mail is not unique");
}
}
}
public class User
{
public int Id { get; set; }
public string Email { get; set; }
}
Network object can have User, but I need to check first in database that given e-mail doesn't already exists or do some other checkings, so my commands will be executed successfully.
By adding user I mean adding completely new User to database.
Would it be correct way to do this?
You can do it the way you do it now and it's ok.
Another option is to make this Validation in Contoller. Then you should use Remote attribute. And Move your IsEmailUnique(string mail) method to Controller.
If you want to know how you can do it with email check - this question will help you.

The right way to build a c#'s app (CF .NET 3.5), i need advice

Over the past two years I developed apps for the CF .NET 3.5 to be runned on warehouse's portable device(windows mobile).
From the beginning I just jumped into the process and made a lot of mistakes that I'm gradually correcting. What has came out are apps made in this way:
a main form to start the whole process which automatically creates a data-form, that will stay alive for the whole time. This data-form will keep all the datas that the user will insert or request from the server. The other forms are basically views of the data with methods to manipulate them.
It works but...am I doing this in the right way? Or maybe am I missing something really fundamental?
So, you created a data form, and you are using it like RAM. You never display the data, you simply store it there to access.
If someone ever has to take over your job (like you leave the company or die), they are going to hate you so bad.
A better technique would be to create a Class that houses all of this data.
The good part is, since you already have a data form, you probably already know how everything is organized!
Now, just use that knowledge of your data to create your class that you can read and write to.
If you have groups of similar items, create other classes that your main class will contain.
If you have several of these similar items, create publically accessible Lists of these items.
Make it as dead simple or as complex as you'd like!
Consider these classes, which are all generic enough to modify however you would need and demonstrate some extras added:
public class DataForm {
private GroupedItem m_item2;
public event EventHandler Item2Changed;
public DataForm() { // this is your constructor
Item1 = new GroupedItem();
Item2 = new GroupedItem();
ItemCollection = new GroupCollectionItems("Group1");
}
public float Value1 { get; set; }
public float Value2 { get; set; }
public GroupedItem Item1 { get; set; }
public GroupedItem Item2 {
get { return m_item2; }
set {
if (m_item2 != value) {
m_item2 = value;
if (Item2Changed != null) {
Item2Changed(this, EventArgs.Empty); // notify whoever is listening for the change
}
}
}
}
public GroupCollectionItems ItemCollection { get; set; }
}
public class GroupedItem {
public GroupedItem() { // this is your constructor
}
public string Name { get; set; }
public object Value { get; set; }
}
public class GroupCollectionItem {
private GroupCollectionItem() { // this is your constructor
}
public static GroupCollectionItem Create(string groupName, string itemName, object itemValue) {
var item = new GroupCollectionItem() {
Group = groupName,
Name = itemName,
Value = itemValue
};
return item;
}
public string Group { get; private set; }
public string Name { get; private set; }
public object Value { get; set; }
}
public class GroupCollectionItems : List<GroupCollectionItem> {
public GroupCollectionItems(string name) { // this is your constructor
Name = name;
}
public string Name { get; private set; }
}

Categories

Resources