Creating a Global Object? - c#

I'm trying to achieve the following:
When a user has been successfully authenticated, I need to create a Global user object which I can access from different Forms (or classes).
I was looking through the Data Sources available in VS, and saw there's a "Object" option which may be suitable for what I'm trying to achieve. The trouble is, I have no idea how it works.
Can anyone point me in the right direction?
Thanks.

Assuming that this is a Windows Forms application, you can create a User class that is stored in a static ApplicationState class.
Steps:
1) Create your user class to hold information about the user:
public class User
{
public string Login { get; set; }
//.. other properties
}
2) Create your ApplicationState class:
public static class ApplicationState
{
public static User CurrentUser { get; set; }
}
3) In your login process, create a new version of the user class and assign it to the ApplicationState.CurrentUser property:
public void CompleteLogin(string sLogin)
{
User user = new User();
user.Login = sLogin;
ApplicationState.CurrentUser = user;
}
4) You can now use ApplicationState.CurrentUser just about anywhere in your project.

It's called a Singleton, and it's a Bad Thing (especially when its state can be mutated). Investigate Dependency Injection (DI) instead. There's even a .NET-specific book on it.
Per request, here's a simple (probably oversimplified) example of doing DI manually. A DI Container library (also known as an Inversion of Control or IoC Container library) can simplify the process of "wiring everything up" in the composition root, and usually also provides lifetime management and other features.
// Composition root of your application
void Main()
{
// Only instance of user we will ever create
var user = new User();
var instance = new MyClass(user);
}
public interface IUser
{
string Name { get; set; }
}
public class User: IUser
{
public string Name { get; set; }
}
public class MyClass
{
public MyClass(IUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
_user = user;
}
private readonly IUser _user;
}

You could use or create a public List making sure that you only add the authenticated users to the List once they have been validated you could even do this via encapsulating field access, create a List or string[] property what you are asking you probably would want to create a class level Property.

Related

C# enable to associate a value to an attribute of an interface

Hi I'm new in development and I'm trying to understand interfaces. Well I understood when to use them but I'm trying to associate a value to an attribute of an interface and I see an error.
public class Consumer : IUser
{
public string Role { get; set; }
public string Consumer { get; set }
}
..
public class Admin : IUser
{
public string Role { get; set; }
public string Admin { get; set; }
}
..
public interface IUser
{
string Role { get; set; }
}
here the code i'm trying to test but I see "Use of unassigned local variable".
IUser user;
string role = "role test";
user.Role = role;
That's fine but I can't create a new instance of IUser because it's an interface. The only solution I found is to create a new Consumer and a new Admin but isn't what I'm trying to do.
My plan is to retrieve the Role attribute from an XML, associate it with the Role of the IUser interface and return it. It'll be a responsibility of another part to check if the role is of an User or Admin
string xmlRole = reader.GetAttribute("Role");
var user = new IUser(); //error
//var user = new Customer(); works but not my plan
//var user = new Admin(); works but not my plan
user.Role = xmlRole;
First of all, interface is an contract, which means it only tells what methods class (which implements that interface) should have.
While coding you can say, for example that given parameter should be of type IUser (Which basically means, that you can assign to it any class as long as it implements IUser).
Example:
interface IUser
{
bool Register();
}
class Administrator : IUser {}
class User : IUser {}
Then, you have method:
public bool HandlerRegister(IUser user)
{
//You can use method here, because you know that class used as parameter will
//implement that method
return user.Register();
}
In your case, when deserializing some XML you need to somehow say that given deserialized object is of type IUser.
But if I were you, I would just create class which represents Role and then, add that class as contract inside interface :)
Then, it would be preaty easy to assign it to all classes that implements yours interface.

Mediatr Notifications on ViewModel in WPF MVVM

While implementing a WPF Application I stumbled on the problem that my application needs some global data in every ViewModel. However some of the ViewModels only need reading access while other need read/write access for this Field. At First I stumbled upon the Microsoft Idea of a SessionContext like so:
public class SessionContext
{
#region Public Members
public static string UserName { get; set; }
public static string Role { get; set; }
public static Teacher CurrentTeacher { get; set; }
public static Parent CurrentParent { get; set; }
public static LocalStudent CurrentStudent { get; set; }
public static List<LocalGrade> CurrentGrades { get; set; }
#endregion
#region Public Methods
public static void Logon(string userName, string role)
{
UserName = userName;
Role = role;
}
public static void Logoff()
{
UserName = "";
Role = "";
CurrentStudent = null;
CurrentTeacher = null;
CurrentParent = null;
}
#endregion
}
This isn't (in my Opinion at least) nicely testable and it gets problematic in case my global data grows (A think that could likely happen in this application).
The next thing I found was the implementation of a Mediator/the Mediator Pattern from this link. I liked the Idea of the Design Norbert is going here and thought about implementing something similar for my project. However in this project I am already using the impressive Mediatr Nuget Package and that is also a Mediator implementation. So I thought "Why reinvent the Wheel" if I could just use a nice and well tested Mediator. But here starts my real Question: In case of sending changes to the global data by other ViewModels to my Readonly ViewModels I would use Notifications. That means:
public class ReadOnlyViewModel : NotificationHandler<Notification>
{
//some Member
//global Data
public string Username {get; private set;}
public async Task Handle(Notification notification, CancellationToken token)
{
Username = notification.Username;
}
}
The Question(s) now:
1. Is this a good Practice for using MVVM (It's just a Feeling that doing this is wrong because it feels like exposing Business Logic in the ViewModel)
2. Is there a better way to seperate this so that my Viewmodel doesn't need to inherit 5 to 6 different NotificationHandlers<,>?
Update:
As Clarification to what I want to achieve here:
My Goal is to implement a wpf application that manages some Global Data (lets say a Username as mentioned above) for one of its Window. That means because i am using a DI Container (and because of what kind of data it is) that I have to declare the Service #mm8 proposed as a Singleton. That however is a little bit problematic in case (and I have that case) I need to open a new Window that needs different global data at this time. That would mean that I either need to change the lifetime to something like "kind of scoped" or (breaking the single Responsibility of the class) by adding more fields for different Purposes or I create n Services for the n possible Windows I maybe need to open. To the first Idea of splitting the Service: I would like to because that would mitigate all the above mentioned problems but that would make the sharing of Data problematic because I don't know a reliable way to communicate this global data from the Writeservice to the readservice while something async or parallell running is happening in a Background Thread that could trigger the writeservice to update it's data.
You could use a shared service that you inject your view models with. It can for example implement two interfaces, one for write operations and one for read operations only, e.g.:
public interface IReadDataService
{
object Read();
}
public interface IWriteDataService : IReadDataService
{
void Write();
}
public class GlobalDataService : IReadDataService, IWriteDataService
{
public object Read()
{
throw new NotImplementedException();
}
public void Write()
{
throw new NotImplementedException();
}
}
You would then inject the view models that should have write access with a IWriteDataService (and the other ones with a IReadDataService):
public ViewModel(IWriteDataService dataService) { ... }
This solution both makes the code easy to understand and easy to test.

Make method to do difference in specific situation

In namespace com.example.website.domain.model, I have Project class, see code:
public class Project
{
private string Name;
private int Status = 0;
... And much more attributes ....
public Project(string name) {
Name = name;
}
public void Publish()
{
Status = 1;
}
public bool IsPublished()
{
return Status == 1;
}
public void ChangeName(string newName)
{
if (IsPublished()) throw new InvalidOperationException("Not allow to change name after published");
Name = newName;
}
public string GetName()
{
return Name;
}
... And much more method ...
}
In normal case, user able to change the name of project if the project is not published yet.
I have to create Admin page that able to change name even project was published. I consider to add new method to Project that is public void AdminChangeName(string name). But I think Project should not expose that kind of method outside admin section (namespace). I want to call same method with same signature without validation.
The only way to define dynamic polymorphism (it is what you need) is to create some kind of compositions. That is you have to extract check logic in some new class.
Let's take a look at some examples.
1.
//in domain namespace
public interface INameChangeStrategy {
public void ChangeName(Project project, string name);
}
//in general use namespace
public class DefaultNameChangeStrategy : INameChangeStrategy {
public void ChangeName(Project project, string name) {
if (project.IsPublished()) throw new InvalidOperationException("Not allow to change name after published");
project.setName(name);
}
}
//in admin use namespace
public class AdminNameChangeStrategy : INameChangeStrategy {
public void ChangeName(Project project, string name) {
project.setName(name);
}
}
As you can see, the problem is in kind of violation of encapsulation. Project itself 'trusts' to strategies and opens its name property to direct change (method .setName(...)).
Also you have to configure strategy properly depending on context of use - admin or not.
2.
Another same solution - add strategy inside Project class:
with interface like
public interface INameChangeCheckStrategy {
public CanChangeName(Project project, string name);
}
//in general use namespace
public class DefaultNameChangeCheckStrategy : INameChangeCheckStrategy {
public void ChangeName(Project project, string name) {
if (project.IsPublished()) throw new InvalidOperationException("Not allow to change name after published");
//other check logic, i.e. regex match
}
}
public class Project
{
private INameChangeCheckStrategy _nameChangeAbilityStrategy;
...
public void ChangeName(string newName)
{
_nameChangeAbilityStrategy.CanChangeName(this, newName);
name = newName;
}
}
in this case encapsulation is holded on a higher level.
Most important thing is that Strategy implementations must be per-request instances in runtime, so project instance to be properly initialized depending on request.
Only the admin role can change the name after publishing? If the answer is yes, here is my answer:
You are mixing concerns, permission or role validation belongs to the application concerns not to your domain (in this case the Project class).
So you shouldn't have a different method for the same action, instead before changing the name you shoud validate if the Project is published and the user has the admin role.
I recommend you this video so much, it talks about how to separate concerns SOLID architecture in slices not layers

Best practice to store temporary information

When my user in the students Role login to the system, he can select various classes that he's enrolled. I already have a filter that'll redirect him to the select class page so he must select a class to access the system, and change it anytime he wants and the whole system's context will change.
As for now, i'm storing IdClass in the session variable, using the code below, and the system uses it to filter all the related queries and functions, like showing all the lessons from the current class. My question is: is this a good practice? Is this right or is there any better and efficient way? I'm trying to follow patterns.
[Serializable]
public sealed class Session
{
private const string SESSION_FOO = "STUDYPLATFORM_GUID";
private Session()
{
this.IdClass= 0; // Construct it to 0 so it evaluate as there's no Class selected.
}
/* This is the session's public IdClass that
i can get and set throughout the application. */
public int IdClass { get; set; }
public static Session Current
{
get
{
if (HttpContext.Current.Session[SESSION_FOO] == null)
{
HttpContext.Current.Session[SESSION_FOO] = new Session();
}
return HttpContext.Current.Session[SESSION_FOO] as Session;
}
}
}

How to pass to a Generic and Pass from a Generic to another class?

When I log into my application, I pass the cUserEntity class which holds all the details of the logged in user, including UserID and Username, to the Dashboard form. From here, I can continue to pass the details around from class to class and form to form. For example (Ignore the generic bit in this example):
Login:
xamlDashboard Manager = new xamlDashboard(_loggedInUser);
Generic Gen = new Generic(_loggedInUser);
Manager.Show();
Dashboard:
cUserEntity _loggedInUser;
public xamlDashboard(cUserEntity loggedInUser)
{
InitializeComponent();
_loggedInUser = loggedInUser;
}
However, I have a Generic.Xaml page which creates a button at the top of every window. Behind the Generic.xaml is a Generic class, which holds the click_event for the created button. The click_event opens a new window to another form.
Now, I need that other form to have the logged in user details, and to do that, I assume I need to pass to the Generic.Xaml and then pass from there to the new form via the click_event. However, as I've read up and noticed, it doesn't seem to be possible as you can't pass a type to a Generic during runtime.
What I hoped to achieved (which failed):
public partial class Generic
{
cUserEntity _loggedInUser;
public Generic(cUserEntity loggedInUser)
{
_loggedInUser = loggedInUser;
}
private void btnHelp_Click(object sender, RoutedEventArgs e)
{
xamlHelp help = new xamlHelp(_loggedInUser);
help.Show();
}
}
Therefore, what is the best and most efficient method to be able to do this, and would appreciate examples, if possible.
It would be alot simpler to create a singleton object to store your logged in user...
public class UserAccount
{
private static User _currentUser;
private UserAccount() {}
public static User CurrentUser
{
set
{
_currentUser = value;
}
get
{
return _currentUser;
}
}
}
Then after login you would do this...
// Set the current User
UserAccount.CurrentUser = user;
Then in any class you need the currently logged in user... you could do...
var user = UserAccount.CurrentUser;
Obviously you would need to implement your own business rules around this but the concept is what I am trying to get across here, a static single instance of the user that can be accessed from anywhere.

Categories

Resources