C#, Android: Delete Singleton - c#

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.

Related

Adding a class to an ICollection List

I have a C# project in which users can log in and create boards. The user class has an ICollection for listing all the boards made by a specific user and I am trying to figure out how to add that board to the list.
These are the two classes, the User class:
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string UserType { get; set; }
public DateTime LastLoginDate { get; set; }
public virtual ICollection<Board> Boards { get; set; }
public virtual ICollection<Post> Posts { get; set; }
And this is the Board class:
public class Board
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
public virtual ICollection<Post> Posts { get; set; }
The aim is that each User would have a list of all the boards that have been added they have created so it is necessary for the board to be added to that list when it is created. This the webform where a board can be added:
public partial class AddBoard : System.Web.UI.Page
{
Board boardToAdd = new Board();
User user = new User();
Utility utility = new Utility();
static User loggedInUser;
protected void CreateButton_Click(object sender, EventArgs e)
{
string name = NameTextBox.Text;
loggedInUser = (User)Session["loggedInUser"];
string checkName = utility.CheckBoardName(name);
if (checkName == "OK")
{
boardToAdd.Name = name;
boardToAdd.DateCreated = DateTime.Now;
user.AddBoard(boardToAdd, loggedInUser);
boardToAdd.AddBoard(boardToAdd);
}
else
{
CreateLabel.Text = checkName;
}
}
And this is the method in the user class I've been trying to use to add the board to the list:
public User AddBoard(Board board, User user)
{
BulletinContext _context = new BulletinContext();
user.Boards.Add(board);
return null;
}
}
For added reference this is the method in the board class I am calling in order to add the board:
public bool AddBoard(Board board)
{
BulletinContext _context = new BulletinContext();
try
{
_context.Boards.Add(board);
_context.SaveChanges();
return true;
}
catch
{
return false;
}
}
}
In your AddBoard, you are adding to a local variable.
After function exit, this is destroyed.
Promote your _context to a class member
As Pieter21 said, the variable _context in Board.AddBoard() is recreated each time you call Board.AddBoard(). As far as I can see, _context should be static and declared outside of the AddBoard() method (since you probably need to access it later).
I've managed to sort out the problem. I just added in code to my method to call the user that the board was being added to and the board to be added.It now looks like this:
public User AddBoard(Board board, User user)
{
BulletinContext _context = new BulletinContext();
User _user = _context.Users.Find(user.ID);
Board _board = _context.Boards.Find(board.ID);
_user.Boards.Add(_board);
_context.SaveChanges();
return null;
}
It's necessary to call this method from the other method that adds the board to the Board class so that it occurs afterwards.

Passing values into private class via { get; }

I am fairly new to the MVVM design pattern and integrated one yesterday in my program with the help of a fellow user here. However, I can't seem to get the values of the variables into another class via the { get; } function. I tried fixing this for quiet some time now and this is my last resort. This is just the script integrated in a wpf form, but the error is here, so I just pasted the code I thought to be neccesary.
public class ViewModel
{
public IEnumerable<string> ServerNames { get; }
= new string[] { "s1", "s2" };
public string SSN { get; set; }
= "s1";
public string APort { get; set; }
= "9999";
public string FPort { get; set; }
= "9991";
public string HostName { get; set; }
= "localhost";
}
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
Now, my thought would be to get the values of the viewmodel by just using { get; }
private class Server
{
public string HostName { get; }
public string APort { get; }
public string FPort { get; }
public string SSN { get; }
}
But this would just leave the 4 variables with a NULL value instead of getting the data from the view model.
How can I get the values of the variables from the view model for further usage into my private class called "Server"?
EDIT:
The server class is initiated later:
private void WPFLoginButton_Click(object sender, RoutedEventArgs e)
{
try
{
Server server = new Server();
HAServerConnection aConnection =
new HAServerConnection(server.HostName, UInt16.Parse(server.APort), new HACalls(), new HErrors());
Of course the values of the properties will be null until you actually set them to some values. You don't seem to be doing this somewhere in your code, and there is no other piece of code that will do it for you.
You could either add setters to the properties and set them when you initialize the Server:
Server server = new Server() { HostName = viewModel.HostName, APort = viewModel.Aport };
Or you could define a constructor that accepts some values and set the properties:
private class Server
{
public Server(string hostName, string aPort, string fPort, string sSN)
{
HostName = hostName;
APort = aPort;
FPort = fPort;
SSN = sSN;
}
public string HostName { get; }
public string APort { get; }
public string FPort { get; }
public string SSN { get; }
}
You will still need to get the actual values from somewhere when you initialize the class, like for example from the view model.

Dynamic method return type in C#

I need your help. I've got the following situation that I have a method with has to determine some conditions and depending on these conditions, returning an object of a specific type.
Now, I do not want to say public object methodXY() with object as return type but I have the approach which does not seem to work yet.
public T methodXY<T>()
{
if (condition A)
return (T)Convert.ChangeType(myValue, typeof(myType));
else if (condition B)
return (T)Convert.ChangeType(myValue, typeof(myOtherType));
else
throw new exception("xyz")
}
But with this, it seems that I have to set the return type already when calling the method. That's what I don't want and don't can.
//myType looks like this
public class myType
{
public string name;
public string firstname;
public string address;
}
and
//myOtherType looks like
public class myOtherType
{
public string name;
public string firstname;
}
Do you need more or more detailed information? Let me know.
Thanks in advance :-)
EDIT:
Here is the complete code sample of the method with object
public object myMethod(MyDto myDto)
{
userHasRoles = GetUserRoles();
if (userHasRoles .Contains("Admin"))
return (mapper.Map<myType>(myDto));
else if (userHasRoles.Contains("User"))
return (mapper.Map<myOtherType>(myDto));
throw new Exception("No elements!");
}
As far as I understand the problem, you need to return a more complete data when the retriever is the admin, and a not-so-complete one when not.
If that is the objective, then you can retrieve the appropriate data from the database and fill in an object of one of the following classes:
public class PersonData {
public string Name { get; private set; }
public string Surname { get; private set; }
}
public class ExtendedPersonData: PersonData {
public string Name { get; private set; }
public string Surname { get; private set; }
public string Address { get; private set; }
}
Since the latter class inherits from the former, you can just create a List<PersonData> and that will cover both cases.
Another, different approach: the data class takes into account the user in order to return or not certain data:
class Person {
public Person(User usr, string address)
{
this.User = usr;
this.address = address;
}
public string User { get; private set; }
public string Name { get; private set; }
public string Surname { get; private set; }
public string Address {
get {
string toret = "N/A";
if ( this.User.IsAdmin() ) {
toret = this.address;
}
return toret;
}
}
private string address;
}
Neither of both solutions is perfect, and both have their own issues, but the problem, at least how you stated it, cannot be solved.
Hope this helps.

Values returned from class revert to null

I create an new Contractor object "gc" that calls a method GetContractor() to return all the properties. The results it is returning is correct, however the "gc" object shows all "NULL". I assume I doing something incorrectly in my aspx.cs page?
aspx.cs
protected void fvWasteCollected_ItemCommand(object sender, FormViewCommandEventArgs e)
{
if (e.CommandName.Equals("Insert")){
ValidationSummaryWasteDetail.ValidationGroup = "WasteReceivedDetail";
if (IsValid) {
odsMRWWasteCollectedDetail.InsertParameters["WasteTypeId"].DefaultValue = ddlWasteCollectedType.SelectedValue;
odsMRWWasteCollectedDetail.InsertParameters["DisposalMethodId"].DefaultValue = ddl_disposalMethod.SelectedValue;
Contractor gc = new Contractor();
gc.GetContractor(2);
var contractorName = gc.MRWContractorName;
}
}
}
.cs
public class Contractor
{
public Contractor GetContractor(int MRWContractorId)
{
using (DataAccessLINQDataContext db = new DataAccessLINQDataContext())
{
var result = db.MRWContractors.Where(c => c.MRWContractorId == MRWContractorId).Select(c => new Contractor
{
MRWContractorId = c.MRWContractorId,
MRWContractorName = c.MRWContractorName,
MRWContractorAddress = c.MRWContractorAddress,
MRWContractorCity = c.MRWContractorCity,
MRWContractorStateCode = c.MRWContractorStateCode,
MRWContractorZipCode = c.MRWContractorZipCode,
MRWContractorPhone = c.MRWContractorPhone,
MRWContractorFax = c.MRWContractorFax,
MRWContractorEmail = c.MRWContractorEmail
}).SingleOrDefault();
return result;
}
}
public int MRWContractorId { get; set; }
public string MRWContractorName { get; set; }
public string MRWContractorAddress { get; set; }
public string MRWContractorCity { get; set; }
public string MRWContractorStateCode { get; set; }
public int? MRWContractorZipCode { get; set; }
public string MRWContractorPhone { get; set; }
public string MRWContractorFax { get; set; }
public string MRWContractorEmail { get; set; }
}
You are loosing the value of gc when you dont assign it to something.
Try this instead:
var contractor = gc.GetContractor(2);
var contractorName = contractor.MRWContractorName;
You are creating one empty instance of the object that is only used to call the GetContractor method. The GetContractor method creates another instance that contains data, which is returned, but you just throw that instance away and expect the data to be available in the first instance that never got populated.
Make the GetContractor method static so that you don't need an instance to call it:
public static Contractor GetContractor(int MRWContractorId)
Now you can call the method to get that instance that contains the data, without first creating an empty instance:
Contractor gc = Contractor.GetContractor(2);
string contractorName = gc.MRWContractorName;

How can I better query multiple domains in Active Directory using C#?

I am attempting to expand a LDAP / AD search from only searching in the currently logged in domain to searching all domains in the AD. The method takes in the string with the query and returns and return an LDAPInformation object.
While I am asking, is there any better way to search for the name than in this way? It is user unfriendly due to needing to use wildcards if looking for a person by last name (example: Doe*).
public static LDAPInformation[] GetGlobalAddressListVIAName(string nameQuery)
{
var currentForest = Forest.GetCurrentForest();
var globalCatalog = currentForest.FindGlobalCatalog();
using (var searcher = globalCatalog.GetDirectorySearcher())
{
using (var entry = new DirectoryEntry(searcher.SearchRoot.Path))
{
searcher.Filter = "(&(mailnickname=*)(objectClass=user)(displayName=" + nameQuery + "))";
searcher.PropertyNamesOnly = true;
searcher.SearchScope = SearchScope.Subtree;
searcher.Sort.Direction = SortDirection.Ascending;
searcher.Sort.PropertyName = "displayName";
return searcher.FindAll().Cast<SearchResult>().Select(result => new LDAPInformation(result.GetDirectoryEntry())).ToArray();
}
}
}
Here is the object:
class LDAPInformation
{
internal LDAPInformation(DirectoryEntry entry)
{
//Section: HASH
this.sAMAccountName = (string)entry.Properties["sAMAccountName"].Value;
//Section: Email
this.Mail = (string)entry.Properties["mail"].Value;
//Section: Organziation
this.Description = (string)entry.Properties["description"].Value;
this.Company = (string)entry.Properties["company"].Value;
this.Title = (string)entry.Properties["title"].Value;
this.Department = (string)entry.Properties["department"].Value;
//Section: Name
this.DisplayName = (string)entry.Properties["displayName"].Value;
this.FirstName = (string)entry.Properties["firstName"].Value;
this.MiddleName = (string)entry.Properties["middleName"].Value;
this.LastName = (string)entry.Properties["lastName"].Value;
//Section: Address
this.StreetAddress = (string)entry.Properties["streetAddress"].Value;
this.City = (string)entry.Properties["city"].Value;
this.State = (string)entry.Properties["state"].Value;
this.PostalCode = (string)entry.Properties["postalCode"].Value;
this.TelephoneNumber = (string)entry.Properties["telephoneNumber"].Value;
}
public string DisplayName
{
get;
private set;
}
public string Mail
{
get;
private set;
}
public string sAMAccountName
{
get;
private set;
}
public string Description
{
get;
private set;
}
public string Company
{
get;
private set;
}
public string Title
{
get;
private set;
}
public string Department
{
get;
private set;
}
public string FirstName
{
get;
private set;
}
public string MiddleName
{
get;
private set;
}
public string LastName
{
get;
private set;
}
public string StreetAddress
{
get;
private set;
}
public string City
{
get;
private set;
}
public string State
{
get;
private set;
}
public string PostalCode
{
get;
private set;
}
public string TelephoneNumber
{
get;
private set;
}
}
#Brian Desmond and #lordzero. Possibly a bit late to the part here, but I've just been working on this sort of stuff myself recently so thought I share.
In response to your question 'What's your search root?", lordzero, here's what you can do to find it from the AD servers without knowing them. A Domain registered PC will know the AD infrastructure/Forest etc.
First you create a DirectoryEntry for "GC://rootDSE"
from that you extract a Naming Context, rootDomainNamingContext or another. You can dump out all the attributes of the first root DSE DirectoryEntry to see what's available.
This is my implementation for a Directory Services service provider we use.
This is taken from a DirectorySearcherWrapper class
I have a member var. and instantiate it in the constructor.
DirectorySearcher directorySearcher;
In my initialisation method, I do this
using (DirectoryEntry directoryEntry = new DirectoryEntry(DirectoryConstants.RootDSE))
{
// Create a Global Catalog Directory Service Searcher
string strRootName = directoryEntry.Properties[DirectoryConstants.RootDomainNamingContext].Value.ToString();
using (DirectoryEntry usersBinding = new DirectoryEntry(DirectoryConstants.GlobalCatalogProtocol + strRootName))
{
directorySearcher.SearchRoot = usersBinding;
directorySearcher.ClientTimeout = timeout;
directorySearcher.CacheResults = true;
result = true;
initialized = true;
}
}
DirectoryConstants class properties
public static string RootDSE { get { return #"GC://rootDSE"; } }
public static string RootDomainNamingContext { get { return "rootDomainNamingContext"; } }
public static string GlobalCatalogProtocol { get { return #"GC://"; } }
I'm sure this only works for Domain users logged in to a Domain registered PC. Authentication is automatically handled behind the scenes. If your user is logged in to a local account or the machine isn't on a Domain, you'll most likely get a DirectoryServicesCOMException.
Hope this helps. Ditch the 'using' constructs if you're not bothered about disposal and StyleCop/Sonar coding violations!
The DirectorySearcherWrapper class where the code above resides is then used by the service provider code. It's separated like this so it can easily be Mocked out as there no guarantee the build machines are registered to a domain when it executes our Unit Tests.
...most of it comes from the MSDN/.Net documentation.
Querying the global catalog is the correct approach.
You might want to look into Ambigous Name Resolution (ANR) - http://support.microsoft.com/kb/243299.

Categories

Resources