In ASP.NET web applications the information about the current session like username, permissions, state, and settings that are needed across the entire application or between postbacks can be stored in the session object. What is the equivalent technique or object for that in MVVM?
From my understanding of MVVM for wpf/windows store apps, the view model is used to store state and there is no concept of a page refresh. Is it normal then to create a SessionViewModel or UserViewModel to store this information that is needed across multiple view models and/or views for a user? Wouldn't this require that every view model have a static reference to it?
So far I have created the following view model to store session information related to a user. So, is it that this view model needs to be passed around some how to other view models and views or is this not how to handle session in MVVM?
public class UserViewModel : ViewModelBase
{
public User Model
{
get;
private set;
}
public string Username
{
get
{
return this.Model.Username;
}
set
{
if (this.Model.Username == value)
{
return;
}
this.Model.Username = value;
RaisePropertyChanged();
}
}
public ObservableCollection<Permission> Permissions
{
get;//TODO
set;
}
public ObservableCollection<Setting> Settings
{
get;//TODO
set;
}
public string Password
{
get
{
return this.Model.Password;
}
set
{
if (this.Model.Password == value)
{
return;
}
this.Model.Password = value;
RaisePropertyChanged();
}
}
public bool Authenticated
{
get
{
return this.Model.Authenticated;
}
set
{
if (this.Model.Authenticated == value)
{
return;
}
this.Model.Authenticated = value;
RaisePropertyChanged();
}
}
public UserViewModel(User model)
{
Model = model;
}
}
Well, if you need a session to store any data (I mean related to both presentstion and model layers) then this approach is ok. Of course if it could be split into logical pieces try to do it.
How do you access this object? I would probably use IOC container to get reference for it. Or even better share smth like this between view models
public interface IUserContext
{
UserViewModel Current { get; }
}
In ASP.Net, the current session (accessible from HttpContext.Current) is nothing more than a static instance that can be accessed, as it is static, from anywhere.
In MVVM, you could just do the same. Build whatever object you need (you can name it CurrentSession), make it static, and access it from your view models. Do note this object doesn't have to be a ViewModel itself (unless you really need to bind its properties on a view).
Say for example you have a LoginViewModel ViewModel for the Login view. You could populate your CurrentSession object in the ValidateUser method of this ViewModel, if the user credentials are valid. Then, anywhere in your viewModels, you could access this CurrentSession object.
Maybe you want a service locator pattern?
In your arbitrary viewmodel, you'll receive the service locator, and do something like this:
public ArbitraryViewModelCtor(IServiceLocator serviceLocator)
{
var authService = serviceLocator.GetAuthenticationService();
var currentLoggedInuser = authService.GetCurrentUser();
}
This seems quite interesting.
Related
I want to make a transition to a reactive view model / model.
I've used 3 scenarios so far:
"ValueA": The model value is only accessed from one view model at a time and the value is only changed through the view model
=> simple property in model, forwarding property with PropertyChanged in view model
"ValueB": The model value is accessed from several view models and/or changes from other sources
=> property with event in model, forwarding property and translation from changed event to PropertyChanged in view model
"ValueC": A value only used in the view model
=> no property in model, property backed by own field with PropertyChanged in view model
This is my "current" approach:
class Model
{
public string ValueA {get;set;}
private string valueB;
public event ValueBChangedEvent ValueBChanged;
public string ValueB
{
get
{
return valueB;
}
set
{
valueB = value;
ValueBChanged();
}
}
}
class ViewModel : INotifyPropertyChanged
{
private Model model;
public string ValueA
{
get
{
return model.ValueA;
}
set
{
model.ValueA = value;
OnPropertyChanged();
}
}
ViewModel()
{
model.ValueBChanged += model_ValueBChanged;
}
private void model_ValueBChanged()
{
OnPropertyChanged("ValueB");
}
public string ValueB
{
get
{
return model.ValueB;
}
set
{
model.ValueB = value;
// no change notification since done via model
}
}
private string valueC;
public string ValueC
{
get
{
return valueC;
}
set
{
valueC = value;
OnPropertyChanged();
}
}
}
This is how I intend to model them using reactive extensions:
class ReactiveModel
{
public string ValueA {get;set;}
private ISubject<string> valueB = new Subject<string>();
public ISubject<string> ValueB
{
get
{
return valueB;
}
}
}
class ReactiveViewModel : INotifyPropertyChanged
{
private ReactiveModel model;
public string ValueA
{
get
{
return ???;
}
set
{
???
}
}
private ReactiveProperty<string> valueB = model.valueB.ToReactiveProperty();
public Reactive<string> ValueB
{
get
{
return valueB;
}
// no setter since access via ValueB.Value which is read-write
}
private ISubject<string> _valueC = new Subject<string>();
private ReactiveProperty<string> valueC = _valueC.ToReactiveProperty();
public ReactiveProperty<string> ValueC
{
get
{
return valueC;
}
// no setter since access via ValueC.Value which is read-write
}
}
Summary:
"ValueA": I have no clue for this case
"ValueB": works at first glance but does neither propagate changes from view model to model nor the other way.
"ValueC": this works as intended
I'd be happy if I had a solution for ValueA and ValueB.
ValueB: View model is responsible for updating model. ReactivePropertyuses only IObservable interface from your model properties and reads values from ValueB(does not write anything).
ReactiveProperty is changed by view through Value property.
ReactiveProperty implements IObservable and you should subscribe to changes to get new values.
ValueA: We can make a ReactiveProperty on the view model side an subscribe to propagate the changed value to the model.
Here is the code for the solution:
class ReactiveModel
{
public string ValueA {get;set;}
private readonly Subject<string> valueB = new Subject<string>();
public IObservable<string> ValueB
{
get
{
return valueB;
}
}
public void UpdateB(string newValue)
{
valueB.OnNext(newValue);
}
}
class ReactiveViewModel
{
private readonly ReactiveModel model;
private readonly ReactiveProperty<string> valueA;
private readonly ReactiveProperty<string> valueB;
public ReactiveViewModel(ReactiveModel model)
{
this.model = model;
valueA = new ReactiveProperty<string>(model.ValueA);
valueA.Subscribe(x => model.ValueA = x);
valueB = model.ValueB.ToReactiveProperty();
valueB.Subscribe(model.UpdateB);
}
public IObservable<string> ValueA
{
get
{
return valueA;
}
}
public ReactiveProperty<string> ValueB
{
get
{
return valueB;
}
}
}
XAML would be in both cases:
<TextBox Text="{Binding ValueA.Value, UpdateSourceTrigger=PropertyChanged}"/>
This is a bit of a contentious topic but I personally don't see property change notification as being specific to the view model and view, I therefore use B but I add INPC to the models as well in my data layer. This can be done in a post-processing build step using Fody or by wrapping the models in a proxy using something like Castle Dynamic Proxy. I personally use the latter, although it requires integration with your ORM so as to not hammer performance i.e. you don't want your database code loading a model object and then thinking that object has changed because you've tried to update it use the proxy wrapper (this is especially true when you turn IList<> into an ObservableCollection).
Your current approach doesn't seem to make a lot of sense. You are implementing events to signal when the Model changes so the View Model can take action. However only the View Model should change the Model, therefore events are completely unnecessary.
The View Model is responsible for making changes to the Model, therefore it should know when a change has been performed, as it is the source of said change.
A pure MVVM approach would be something like this:
public class MyModel
{
public string MyValue { get; set; }
...
}
public class MyViewModel
{
private MyModel _Model;
public string MyModelValue
{
get { return _Model.MyValue; }
set
{
_Model.MyValue = value;
//Notify property changed.
}
}
...
}
It is not the responsibility of the Model to notify the View of changes, instead it is the responsibility of the ViewModel to signal these changes. The Model should not be exposed to the View, but instead the properties of the Model that the View requires should be exposed.
Think of it this way.
The user changes the MyModelValue property in a TextBox on the View.
The View notifies the ViewModel of the change.
The ViewModel changes the Model.
The only purpose of INotifyPropertyChanged is when the above process is reversed, where the ViewModel needs to tell the View that a property has changed:
A method in the ViewModel is called that updates MyModelValue.
The ViewModel notifies the View of the change.
The View updates the TextBox.
The pattern of exposing only properties of the Model that the view requires is not always followed, instead you may see the entire Model being exposed to the View, but as I have said many times before, MVVM is a pattern, not the law. Implementing INotifyPropertyChanged in the Model is perfectly acceptable.
This is actually 2 questions in one.
I have an asp.net mvc application where I have to load a list of Modules, its just a simple list with ID, modulename and a class name to render it on the view with font awesome.
My model is like this:
public class Module
{
[Key]
public int Id { get; set; }
public string ModuleName { get; set; }
public string FontAwesomeClass { get; set; }
}
Because the module list is a Partial View that will render some icons on the top navigation bar, I dont want that for each refresh of the app, it goes to the DB, so it must be cached(I am using Azure REDIS Cache, not relevant for the question anyway), so instead of calling the DB context directly from the controller, I am calling a Cache Class that will check if the cache object exists, if not it will retrieve it from DB, if it does, it will return it from cache.
This my solution structure:
http://screencast.com/t/uayPYiHaPCav
Here is my controller Module.cs
public ActionResult GetModules()
{
return View(Cache.Module.GetModules());
}
As you can see the Controller does not have any logic where to get the data from.
Here is the Module.cs (on the Cache Namespace)
public class Module
{
private AppDataContext dbApp = new AppDataContext();
//Load modules from cache or from database
public static List<Models.Module> GetModules()
{
IDatabase cache = Helper.Connection.GetDatabase();
List<Models.Module> listOfModules = (List<Models.Module>)cache.Get("Modules");
if (listOfModules == null)
{
return dbApp.ModuleList.ToList();
}
else
{
return listOfModules;
}
}
}
Here I have a compiler error which I am not sure how to best fix it:
Error CS0120 An object reference is required for the non-static field,
method, or property 'Module.dbApp'
So that was my first question.
The 2nd question is more about the design pattern, do you consider this correct or not? the way I am trying to get the data from Cache, and its actually the Cache class which checks if data is on it or if it has to go to the DB.
First Question: make your private member static
private static AppDataContext dbApp = new AppDataContext();
2nd Question: your cache strategy seems pretty standard. The only thing is that you might want to expire cache data. For example, the cached data can get old and the longer it stays in the cache the older it gets. You might at some point want to expire it and get fresh data again.
Update:
#EstebanV for code sample (this off the top of my head, don't assume that it compiles):
/**
ICachedPersonDao abstracts away the caching mechanism
away from the core of your application
**/
public CachedPersonDao : ICachedPersonDao
{
private IPersonDao personDao = null;
public CachedPersonDao(IPersonDao personDao)
{
this.personDao = personDao;
}
public Person GetPersonById(int id){
bool isInCache = CACHE.SomeFunctionThatChecksInYourCache(id);
if (isInCache)
{
return CACHE.SomeFunctionThatReturnsTheCachedPerson(id);
}
else
{
//Well it's not in the cache so let's get it from the DB.
return this.personDao.GetPersonById(id);
}
}
}
/**
IPersonDao abstracts database communication
away from the core of your application
**/
public class PersonDao : IPersonDao
{
public Person GetPersonById(int id)
{
/** Get the person by id from the DB
through EntityFramework or whatever
**/
}
}
Usage:
In your controller, use ICachedPersonDao if you want to attempt to get from cache or use IPersonDao if you want to get it directly from the database without checking the cache.
Like I said, you should learn Dependency Injection it will help "inject" these dependencies into the classes that uses them.
I say again, this is off the top of my head. It won't compile. It's just to illustrate the concept.
I have a WPF application with MVVM.As I understood, the main goal of MVVM is to separate between logic layer and UI layer.
I have this Model class :
public class User
{
public string Login{get;set;}
public string Pwd{get;set;}
public List<User> GetUsers()
{
//
}
}
in my ViewModel, I instanciate a User object and an ObservableCollection of User
public class UserVM
{
public User _User{get;set;}
public ObservableCollection<User> liste{get; private set;}
public UserVM()
{
_User = new User("TODO","PWD2");
liste = new ObservableCollection(_User.GetUsers);
}
}
I feel that I bind directly a UI properties to a model object,So I need To know :
When I bind UI properties to the object _User properties, did I respect the MVVM architecture?
When I bind a listview datasource to liste, did I respect the MVVM architecture?
For the first question, if it is not suitable for MVVM, is it better to expose the model's properties instead of declaring the class?
For the second question, if it is not suitable for MVVM, How can I fix it ?
Thanks,
It looks like your User class has a tree-like structure in that it contains a List of User objects which themselves may contain a List of User objects...
The problem here is that your view model class contains User objects. Only the UserVM model would contain an ObservableCollection for example.
A simple fix would be: EDIT user.GetUsers() doesn't return a List<UserVM>
public class UserVM
{
public string Login { get; set; }
public string Pwd { get; set; }
public ObservableCollection<UserVM> Users { get; private set; }
public UserVM(User user)
{
Login = user.Login;
Pwd = user.Pwd;
Users = new ObservableCollection<UserViewModel>(
user.GetUsers().Select(subUser => new UserViewModel(subUser)));
}
}
You may also want to implement INotifyPropertyChanged so that the view gets notifications that the view model has changed.
I am having a problem understanding how to propagate a property changed event in a Model class up through the ViewModel and into the view. I am trying to conform to the MVVM pattern so please keep that in mind.
I have a Model that I am trying to expose by the ViewModel. My Model class queries an Api call to get the server status and exposes that status in public properties. Ex:
public class ServerStatusRequest : ApiRequest
{
//Exposable properties by request
public ServerStatusHelperClass Status { get; set; }
Where ServerStatusHelperClass is just a wrapper for the combined results in the query:
public class ServerStatusHelperClass
{
public bool ServerStatus { get; set; }
public int OnlinePlayers { get; set; }
The cool thing about my ApiRequest base class is that it checks the cache time of a particular Api call and updates the Results by using a System.Timers.Timer. So, for example, the ServerStatus Api call is cached for 3 minutes on the Api, so every 3 minutes my ServerStatusApiRequest object will have fresh data for it. I expose a UpdatedResults event in all ApiRequest classes to notify when new data comes in.
Now I want my ViewModel to have an instance of ServerStatusApiRequest and bind to its ServerStatusHelperClass Status property and stay up to date with the changes every time the information is updated, but my view (for binding) can't know about my model, and thus, doesn't know about my UpdatedResults event in my ApiRequest class. How can I reflect that out to the View through my ViewModel? Am I doing something completely weird here?
Here is what I have that is semi-working but I feel is a very hacky solution:
In my ViewModel:
public const string EveServerStatusPropertyName = "EveServerStatus";
private ServerStatusRequest _eveServerStatus = new ServerStatusRequest();
public ServerStatusRequest EveServerStatus
{
get
{
return _eveServerStatus;
}
set
{
//if (_eveServerStatus == value)
//{
// return;
//}
//RaisePropertyChanging(EveServerStatusPropertyName);
_eveServerStatus = value;
RaisePropertyChanged(EveServerStatusPropertyName);
}
}
public void UpdateEveServerStatus(object sender, EventArgs e)
{
EveServerStatus = (ServerStatusRequest)sender;
}
And in the ViewModels constructor I subscribe to the Model's event:
EveServerStatus.UpdatedResults += new UpdatedResultsEventHandler(UpdateEveServerStatus);
As you can see, this seems extremely redundant. And I also ran into a problem where I had to comment out the check in the setter for EveServerStatus because at that point the _eveServerStatus was already updated to value just without it knowing and I wanted to fire the event anyway.
I fell like I'm missing a key concept here to link this all together much more easily.
Thanks for any input.
I have come across a much better way to implement the behavior I was looking for. Here is the code in my ViewModel:
private ServerStatusRequest _eveServerStatus = new ServerStatusRequest();
public ServerStatusRequest EveServerStatus
{
get
{
return _eveServerStatus;
}
}
No setter as my ViewModel nor my View should be changing this data. And Inside my ServerStatusRequest class I have a property exposing the ServerStatusHelperClass object as shown in the Question. I have changed the ServerStatusHelperClass and made it implement INotifyPropertyChanged as so:
public class ServerStatusHelperClass : ObservableObject
{
private bool _serverStatus;
public bool ServerStatus
{
get
{
return _serverStatus;
}
set
{
_serverStatus = value;
RaisePropertyChanged("ServerStatus");
}
}
...
ObservableObject is just a simple class that implements INotifyPropertyChanged for me from mvvmlight.
By doing this my View is automatically updated when my ApiRequest class modifies it's ServerStatusHelperClass object.
Input on this solution is welcome.
I wrote a simple WPF Application as an example:
Model:
public class User
{
public String FirstName { get; set; }
public String LastName { get; set; }
}
ViewModel:
//ViewModelBase contains base code for INotifyPropertyChanged
public class UserViewModel : ViewModelBase
{
public UserViewModel(User user)
{
_user = user ?? new User();
}
private User _user;
public String FirstName
{
get { return _user.FirstName; }
set
{
if (_user.FirstName != value)
{
_user.FirstName = value;
RaisePropertyChanged("FirstName", "Full Name");
}
}
}
public String LastName
{
get { return _user.LastName; }
set
{
if (_user.LastName!= value)
{
_user.LastName= value;
RaisePropertyChanged("LastName", "Full Name");
}
}
}
public String FullName
{
get { return String.Format("{0}, {1}", LastName, FirstName); }
}
}
Can I reuse my code in an MVC3 app? I figure the INotifyPropertyChanged stuff won't work, but can't I still reuse the ViewModel somehow?
No, not really. ViewModels and Controllers are governed by completely different design patterns.
Where MVVM and MVC shine is that they help break out business logic from your codebehind. You quite possibly can share your support code (code that you call from your VMs and Controllers but that isn't touched by any platform-centric designs) and models (depending on how they are coded).
I'm currently working on an app that combines an MVC website and a WPF application, and I do share models between them, and as much code as I can squeeze from my VMs and Controllers. But there is too much different between the two to use your VMs as Controllers and vice versa.
Your 'firstname' and 'lastname' method would just move into the model, as they aren't too much more than slightly more fancy getters and setters.
You're FullName method I'd be tempted to put in the controller as it's dealing with formatting but it does kind of have a basic and testable logic behind it.
As you say, I'm not sure you could use the NotifyProperty gubbins, but the methods in general should port over happily.