I have a WPF Application where I register many users in my apps inner Data Base. I have many classes that would like to query which user is logged in currently.
I wonder which is the best architecture for this kind of scenario.
So far I can think of:
A Singleton object storing the current logged in User.
Use Dependency Injection and pass an object containing all the login information for every class that needs it (and to some classes that won't need it directly, but might have to pass it along to another one later).
Singleton has its disadvantages, and DI could lead to many dependencies being shared all over the place and could be a maintenance nightmare on the furniture. I wonder if there is a better solution for this issue.
Related
I have a react app, an object with permissions comes from the backend and depending on the user's role or selected permissions, the user has access to one or another functionality in different components(buttons, certain table cells, etc.)
What is the best way to implement this functionality on the front-end side? I thought that you can use a certain service that will accept all permissions and, using the API context. For example, already scatter them throughout the application, depending on the component. Is this the normal way and how can you do it better?
I have a little silly sketch of how I see it, I would like to know how to do it better.
https://codesandbox.io/s/modest-joliot-nkur7?file=/src/App.js
Scattering any logic through out an application sounds like a poor design choice for any feature. Instead you should have centralized code that does this. For example, this could be a function that you can call as needed such as hasPermission().
I had a talk with teamlead about this topic and from his point of view we can just use bindings and commandings omitting ViewModel, because we can test UI behaviour without VM using Automation or our own developed mechanisms of UI testing (based on automated clicks on Views). So, if there are no real benefits, why should I spawn "redundant" entities? Besides, automated integration tests look much more indicative than VM tests. So, it seems that we can mix VMs and Models.
update:
I agree that mixing VMs and Models brings into single .cs a data model and rules of data transformation for representing it in a View. But if this is only one benefit - I don't want to create a VM for each View.
So what pros of VM do you know?
The VM is the logic behind your UI. combining the UI code with the logic ends up in a mess, at least from my experience. Your view should define what you see - buttons, menus etc. Your VM is in charge of the binding and handling events caused by the user.
Edit:
Not wanting to create a VM for each view doesn't sound like a SW-oriented reason. Doing so will leave your view clean of logic and your model free to be the connecting layer between the core layer and your app layer.
I like the following example referring to the model and its role (why it shouldn't be combined with the VM): imagine you're developing some Android app using Google maps. Google maps are your core. Then one fine day you really need the option to, say, color parts of the map in pink, bright pink. An email to Google asking for colorPink(Map)will probably get you nowhere. That's where your model steps in and provides you the map wrapper that you need to define your pinky method.
Without a separate model, you'd have to go through every VM that uses map and update it.
So, the view has a role, the model has a role, the VM is the logic between those.
Edit 2:
There are some cases where there's no need of a model layer - I tended to disagree at first but was convinced after a discussion: In relatively small applications, the model can end up being a redundant wrapper with no added functionality over the core. In such cases, you can use the core objects directly.
What is he binding to? Whatever he is binding to is effectively a view model, whether you call it that or not. If it also doubles as a data model, then you're violating the Single Responsibility Principal (SRP). Essentially, the problem here is that you're lumping together code that is servicing different parts of the application architecture, which will lead to a convoluted mess.
UI Testing is a pain not just because you need to accomodate for changes in the View which can occur many times but also because UI tends to interfere with its own testing. Depending on the tests needed you'll need to keep track of focus, resize and possibly other (mouse) events which can be extremely hard to make it a representative test.
It is much easier to scope the test to the logic in the ViewModel and leave the UI testing to humans. The human testers do not need to test the logic; their only consern should be the UI.
By breaking down a ViewModel into a hierarchy of ViewModels you might be able to reuse a ViewModel multiple times. There is no rule that states that you should have a ViewModel for each View. (After a release or two I end up there but that's besides the point :) )
It depends on the nature of your Model - sometimes they are simple and can serve as both like you are suggesting. However, depending on the framework, you'll need to dirty up your model with some PropertyChanged event code which can get messy and distracting. In more complex cases, they serve as a mediator between your the view and the model. Let's suppose you're creating a client app that monitors a remote process or database entries - creating View Model's for these entities let's you surface your data in a way that is convenient to bind to for a UI framework (but is silly in a DB framework), encapsulate operations as commands, perform validation, etc etc.
I am Java programmer who tries to investigate CakePHP - currently I have problem with application structure/design. I could not understand where to put core logic of application.
When I am developing in JavaEE, common approach looks like following:
Model classes are simple beans which represent data entities (products, people etc) - mostly like data structures with getters/setters;
Controller classes are simple enough classes which aggregate necessary data and inject them into dedicated View template which is then sent to user;
DAO (DataAccessObject) or Repository classes are ones which can load and store entities into database;
Service classes are usually singletons which contains certain business-logic methods - these are called by controllers, by other services or by scheduled actions, on the other hand they themselves call DAO / Repository methods to fetch or modify data.
For example if I have entities Person, Product and Order, when user selects some product and clicks "put it into my cart/basket" new Order for this Person should be created and this Product should be added to this Order (we may check that Person is not bad debtor and that Product is present at store etc.) - all this work is performed in methods of OrderService called by some controller.
Usually some kind of IOC (Inversion of Control) is used so that all services and controllers have links to necessary services etc.
Now I am slightly bewildered about how this all is done in CakePHP. Where should I put this business-logic etc. ?
In CakePHP the model layer is made up from collection of active record instances, called AppModel. They combine the storage-related logic (that you would usually put in DAOs and/or Repositories) with business logic (what usually went into your "models").
Any other domain related logic (from your Service) becomes part of controller.
If you want to know, how you are supposed to implement domain business logic in CakePHP, just look up articles which praise active record pattern.
Personal opinion
CakePHP and CodeIgniter are two of the worst frameworks in PHP. They are filled with bad practices.
Actually, if you were doing correct-ish MVC, then model layer would contain all of the business logic and everything that is related to it. Model layer is made of DAOs, Repositories, Domain Objects (what you call "models") and Services.
While your descriptions of Java-based code indicates, that you are kinda moving in that direction, CakePHP is not even remotely close to it.
Then again, it might be that my understanding of MVC is just wrong.
The controllers should only contain logic relevant for the whole thing being a web application. Your business logic belongs into the models. I think it is one of the basic mistakes that you find in many cakePHP applications, that to much logic is put into the controllers, which actually belongs into the models.
In CakePHP. the "M" is just a bunch of Data Models instead of Domain Models.
In my opinion. CakePHP is made for RAD development. It is not a good fit for enterprise applications.
My opinion though.
I am following the example from Local Database for Windows Phone. From it, I learned how to create a local database in my app and pull a data to a page.
What I am looking for now is to show the data not in one page but three pages of my app. So, what are my ways to do this? Can I make an object in app.xaml and access it in the pages?
Kindly advise me.
thanks.
The approaches all boil down to your views on the architecture and how testable you want your application to be.
Whilst you could put some reference to the data context on your application object, you're then increasing the linkage between the view-models and the views; Arguably nothing in the view-models needs to know anything about anything in the views (and I'm in the camp where all xaml counts as part of the views). With this in mind, one alternate would be to have something in your view-models (or even your models) that is a static class that exposes application level objects (in a manner that is unit-test friendly, and perhaps even sharable amongst platforms) and allows any of your view-models access to that datacontext and construct any of your models, etc.
As a very rudimentary scenario, let's take these two operations:
UserManager.UpdateFirstName(int userId, string firstName)
{
User user = userRepository.GetById(userId);
user.FirstName = firstName;
userRepository.SaveChanges();
}
InventoryManager.InsertOrder(Order newOrder)
{
orderRepository.Add(newOrder);
orderRepository.SaveChanges();
}
I have only used EF in web projects and relied heavily on the stateless nature of the web. With every request I would get a fresh copy of the context injected into my business layer facade objects (services, managers, whatever you want to call them), all of the business managers sharing the same instance of the EF context. Currently I am working on a WPF project and I'm injecting the business managers and subsequently the repositories that they use directly into the View Model.
Let's assume a user is on a complicated screen and his first button click calls the UpdateFirstName() method. Let's assume SaveChanges() fails for whatever reason. Their second button click will invoke the InsertOrder() method.
On the web this is not an issue as the context for operation #2 is not related (new http request) to the context used by operation #1. On the desktop however, it's the same context across both actions. The issue arises in the fact that the user's first name has been modified and as such is tracked by the context. Even though the original SaveChanges() didn't take (say the db was not available at that time), the second operation calling SaveChanges() will not only insert the new order, it will also update the users first name. In just about every cause this is not desirable, as the user has long forgotten about their first action which failed anyway.
This is obviously being a silly example, but I always tend to bump into these sort of scenarios where I wish I could just start fresh with a new context for every user action as opposed having a longer lived (for the life of the WPF window for example) context.
How do you guys handle these situations?
A very real interrogqation when coming from ad hoc desktop apps that hit the database directly.
The answer that seems to go with the philosophy for ORMs is to have a context that has the same lifespan as your screen's.
The data context is a Unit Of Work implementation, in essence. For a web app, it is obviously the request and it works well.
For a desktop app, you could have a context tied to the screen, or possibly tied to the edit operation (between loading and pressing "save"). Read only operations could have a throwaway context (using IDs to reload the object when necessary, for example when pressing a "delete button" in a grid).
Forget about a context that spans the entire application's life if you want to stay aware of modifications from other users (relationship collections are cached when first loaded).
Also forget about directly sharing EF entities between different windows, because that effectively makes it an app-wide and thus long lived context.
It seems to me ORMs tend to enforce a web-like design on desktop apps because of this. No real way around this I'm afraid.
Not that it is necessary a bad thing in itself. You should normally not be attacking the database at the desktop level if it is to be shared between multiple instances. In which case you would be using a service layer, EF would be in its element and your problem would be shifted to the "service context"...
We have a large WPF application that calls WCF services to perform CRUD operations like ‘UpdateFirstName()’ or ‘InsertOrder()’. Every call into the service creates a new ObjectContext, therefore we don’t need to worry about inconsistent ObjectContexts hanging around.
Throw away the ObjectContext as soon as you are done with it. Nothing’s wrong with generating a new ObjectContext on the fly. There’s unnoticeable overhead in creating a new ObjectContext and you’ll save yourself many future bugs and headaches.
Suppose you do create a new ObjectContext each time a method is called on your repository, the below snippet would still give you transaction support by using the TransactionScope class. For example,
using (TransactionScope scope = new TransactionScope())
{
UserManager.UpdateFirstName(userid,firstName);
InventoryManager.InsertOrder(newOrder);
scope.Complete();
}
One completely different way is writing all changes to the database directly (with short lived database contexts). And then add some kind of draft/versioning on top of that. That way you can still offer ok/undo/cancel functionality.