MVVM and Repository Question - mvvm

Let's say that I have two views in my app, MemberListView and MemberEditView. They are associated with their perspective viewModels, MemberListViewModel and MemberEditViewModel. The models speak to a repository class, MemberRepository, which has the CRUD methods for the member class.
In the MemberEditView form, I have several dropdowns that display thinkgs like Status (Active/Inactive/Pending), the members trade code etc. They are ObservableCollection objects in my viewModel and are bound to ComboBoxes on the view. Should the MemberRepository handle the gets for retrieving the lists of each to be displayed?
What if on the MemberEditView I have a grid that displays all the jobs that the member has had over the years. If the user doubleclicks one of the jobs, it calls a JobHistoryEditView to display the job Information and it has a JobHistoryViewModel. Should the MemberRepository take care of the JobHistory CRUD methods or should I have a separate JobHistory Repository?

Most MVVM applications would have this architecture:
View -> ViewModel -> Model -> Repository
I have recently been espousing a variant:
View -> ViewModel <- Presenter -> Model -> Repository
(Where A -> B means "A knows about B", but B doesn't know about A.)
Notice that in both cases, the only thing that knows about the repository is the Model, not the ViewModel. Your model isn't just the domain entities, it also has to house the business logic. Obviously one of the user stories your business logic has to support is something I'll call a MemberEditTask:
public class MemberEditTask
{
private readonly Member _member;
public MemberEditTask(Member member, IRepository repository)
{
this._member = member;
this.StatusChoices = repository.GetPossibleMemberStatuses(member);
}
public ReadOnlyCollection<MemberStatus> StatusChoices { get; private set; }
public MemberStatus Status
{
get { return this._member.Status; }
set
{
if(!this.StatusChoices.Contains(value))
{
throw new ArgumentOutOfRangeException();
}
this._member.Status = value;
}
}
}
All of this logic belongs in your Model because the list of possible choices (and validating that one of those was actually chosen) is defined by business logic. You could also imagine some other thing consuming the MemberEditTask, like an automated process running on the server that edits a member in response to a file uploaded on an FTP server, or a background process (setting the status to Inactive after a certain amount of time). All of those things need to execute the same business rules, so it all has to be common (not in the ViewModel).
So given that class, the ViewModel class looks like this:
public class MemberEditViewModel : ViewModelBase
{
private readonly MemberEditTask _task;
public MemberEditViewModel(MemberEditTask task)
{
this._task = task;
}
public IEnumerable<MemberStatus> StatusChoices
{ get { return this._task.StatusChoices; }
public MemberStatus Status
{
get { return this._task.Status; }
set
{
this._task.Status = value;
NotifyAllPropertiesChanged();
}
}
}
In this case, as a very simple convenience, just believe that NotifyAllPropertiesChanged is a protected method of ViewModelBase that uses reflection to raise a PropertyChanged event on all public properties of the ViewModel. :) That's overkill of course, but it drives at a more important point...
This is almost a silly example because in this case, MemberEditViewModel is unnecessary. If the View is the only one setting Status then there's really no need to raise the property changed event either! Of course in the real world, you will have more properties and there will be interactions. The reason for the ViewModel to exist is to notify consumers when its view-related properties change, which is something the Model doesn't do (and shouldn't in my opinion). (The ViewModel also has extra View-specific logic to support animations, etc.)
So back to your question... whether or not the MemberRepository is responsible for executing the gets of the statuses is irrelevant from the point of view of the ViewModel because the repository is a service used by the Model. The Model is a service used by the ViewModel. Make your Model of the task/workflow/process/whatever expose the list of status options.
Sorry if that was long-winded.

Related

EF Core load references of unknown entity

DISCLAIMER: Since we are all familiar with it, i will be using contoso university design to explain my question. Also, i am using EF core and .net core 2.0 on a mvc code first design.
I am developing a very generic RESTful API that works on any model. It has one method for each of create, read, update and delete operation in only one controller, the route of this is
[Route("/api/{resource}")]
Resource is the entity that the client wants to work with, for example if someone wants to get all Courses using the api he has to do a GET request on http://www.example.com/api/course/ or http://www.example.com/api/course/2 to get one by id and the following code will do the job.
[HttpGet("{id:int:min(1)?}")]
public IActionResult Read([FromRoute] string resource, [FromRoute] int? id)
{
//find resourse in models
IEntityType entityType = _context.Model
.GetEntityTypes()
.FirstOrDefault(x => x.Name.EndsWith($".{resource}", StringComparison.OrdinalIgnoreCase));
if (entityType == null) return NotFound(resource);
Type type = entityType.ClrType;
if (id == null)//select all from table
{
var entityRows = context.GetType().GetMethod("Set").MakeGenericMethod(type).Invoke(context, null);
if (entityRows == null)
return NoContent();
//TODO: load references (1)
return Ok(entityRows);
}
else //select by id
{
var entityRow = _context.Find(type, id);
if (entityRow == null)
return NoContent();
//TODO: load references (2)
return Ok(entityRows);
}
}
This small piece of code will do the magic with one small exception, intermediate collections will not be loaded. Given our example, the fetched course or courses will have no info for CourseInstructor (the intermediate collection in between Course and Person). I am trying to find a way to Eager load the navigation properties only if it is a collection; or by any other condition that will ensure that only many-to-many relationships are loaded.
For //TODO: load reference (2) i could use
_context.Entry(entityRow).Collection("CourseInsructor").Load();
On runtime if i could find all the navigation properties (filtered by spoken condition) and foreach of them i did Load(), i should get the desired result. My problem is when i get all (when id is null) the entityRows is type 'InternalDbSet' which is an unknown model.
So for the two TODOs i need some help on doing the following steps
1: find navigation properties of many-to-many relationships only
2: load them
Any suggestions?
In general, this seems like a very bad idea to me. While the CRUD stuff is going to be identical for most resources, there will be variances (as you've now run into). There's also something to be said for having a self-documenting API: with individual controllers, you know which resources can be accessed by nature of having a controller associated with that resource. With they way you're doing it, it's a complete black box. This also will of course effect any sort of actual generated API documentation. For example, if you were to include Swagger in your project, it would not be able to determine what you're doing here. Finally, you're now having to use reflection for everything, which will effect your performance.
What I would suggest instead is creating a base abstract controller and then creating a controller for each unique resource that inherits from that, for example:
public abstract class BaseController<TEntity> : Controller
where TEntity : class, new()
{
protected readonly MyContext _context;
public BaseController(MyContext context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
...
[HttpGet("create")]
public IActionResult Create()
{
var model = new TEntity();
return View(model);
}
[HttpPost("create")]
public async Task<IActionResult> Create(TEntity model)
{
if (ModelState.IsValid)
{
_context.Add(model);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(model);
}
...
}
I just wanted to give a quick example, but you'd build out all the rest of the CRUD methods in the same fashion, generically using TEntity. Then, for each actual resource, you simply do:
public class WidgetController : BaseController<Widget>
{
public WidgetController(MyContext context)
: base(context)
{
}
}
No duplication of code, but you've now got an actual real controller backing the resource, aiding both the innate and possibly explicit documentation of your API. And, no reflection anywhere.
Then, to solve problems like what you have here, you can add hooks to your base controller: essentially just virtual methods that are utilized in your base controller's CRUD actions and do nothing or just default things. However, you can then override these in your derived controllers to stub in additional functionality. For example, you can add something like:
public virtual IQueryable<TEntity> GetQueryable()
=> _context.Set<TEntity>();
Then, in your derived controller, you can do something like:
public class CourseController : BaseController<Course>
{
...
public override IQueryable<Course> GetQueryable()
=> base.GetQueryable().Include(x => x.CourseInstructors).ThenInclude(x => x.Instructor);
So, for example, you'd make your BaseController.Index action, perhaps, utilize GetQueryable() to get the list of entities to display. Simply by overriding this on the derived class, you can alter what happens based on the context of a particular type of resource.

Using Reactive Extensions to stream model changes

I am working on a server component which is responsible for caching models in memory and then stream any changes to interested clients.
When the first client requests a model (well model key, each model has a key to identify it) the model will be created (along with any subscriptions to downstream systems) and then sent to the client, followed by a stream of updates (generated by downstream systems). Any subsequent client's should get this cached (updated) model, again with the stream of updates. When the last client unsubscribes to the model the downstream subscriptions should be destroyed and the cached model destroyed.
Could anyone point me in the right direction as regards to how Rx could help here. I guess what isn't clear to me at the moment is how I synchronize state (of the object) and the stream of changes? Would I have two separate IObservables for the model and updates?
Update: here's what I have so far:
Model model = null;
return Observable.Create((IObserver<ModelUpdate> observer) =>
{
model = _modelFactory.GetModel(key);
_backendThing.Subscribe(model, observer.OnNext);
return Disposable.Create(() =>
{
_backendThing.Unsubscribe(model);
});
})
.Do((u) => model.MergeUpdate(u))
.Buffer(_bufferLength)
.Select(inp => new ModelEvent(inp))
.Publish()
.RefCount()
.StartWith(new ModelEvent(model)
If I understood the problem correctly, there are Models coming in dynamically. At any point in time in your Application's lifetime, the number of Models are unknown.
For that purpose an IObservable<IEnumerable<Model>> looks like a way to go. Each time there is a new Model added or an existing one removed, the updated IEnumerable<Model> would be streamed. Now it would essentially preserve the older objects as opposed to creating all Models each time there is an update unless there is a good reason to do so.
As for the update on each Model object's state such as any field value or property value changed, I would look into Paul Betts' ReactiveUI project, it has something called ReactiveObject. Reactive object helps you get change notifications easily, but that library is mainly designed for WPF MVVM applications.
Here is how a Model's state update would go with ReactiveObject
public class Model : ReactiveObject
{
int _currentPressure;
public int CurrentPressure
{
get { return _currentPressure; }
set { this.RaiseAndSetIfChagned(ref _currentPressure, value); }
}
}
now anywhere you have Model object in your application you could easily get an Observable that will give you updates about the object's pressure component. I can use When or WhenAny extension methods.
You could however not use ReactiveUI and have a simple IObservable whenever a state change occurs.
Something like this may work, though your requirements aren't exactly clear to me.
private static readonly ConcurrentDictionary<Key, IObservable<Model>> cache = new...
...
public IObservable<Model> GetModel(Key key)
{
return cache.GetOrAdd(key, CreateModelWithUpdates);
}
private IObservable<Model> CreateModelWithUpdates(Key key)
{
return Observable.Using(() => new Model(key), model => GetUpdates(model).StartWith(model))
.Publish((Model)null)
.RefCount()
.Where(model => model != null);
}
private IObservable<Model> GetUpdates(Model model) { ... }
...
public class Model : IDisposable
{
...
}

Decouple EF queries from BL - Extension Methods VS Class-Per-Query

I have read dozens of posts about PROs and CONs of trying to mock \ fake EF in the business logic.
I have not yet decided what to do - but one thing I know is - I have to separate the queries from the business logic.
In this post I saw that Ladislav has answered that there are 2 good ways:
Let them be where they are and use custom extension methods, query views, mapped database views or custom defining queries to define reusable parts.
Expose every single query as method on some separate class. The method
mustn't expose IQueryable and mustn't accept Expression as parameter =
whole query logic must be wrapped in the method. But this will make
your class covering related methods much like repository (the only one
which can be mocked or faked). This implementation is close to
implementation used with stored procedures.
Which method do you think is better any why ?
Are there ANY downsides to put the queries in their own place ? (maybe losing some functionality from EF or something like that)
Do I have to encapsulate even the simplest queries like:
using (MyDbContext entities = new MyDbContext)
{
User user = entities.Users.Find(userId); // ENCAPSULATE THIS ?
// Some BL Code here
}
So I guess your main point is testability of your code, isn't it? In such case you should start by counting responsibilities of the method you want to test and than refactor your code using single responsibility pattern.
Your example code has at least three responsibilities:
Creating an object is a responsibility - context is an object. Moreover it is and object you don't want to use in your unit test so you must move its creation elsewhere.
Executing query is a responsibility. Moreover it is a responsibility you would like to avoid in your unit test.
Doing some business logic is a responsibility
To simplify testing you should refactor your code and divide those responsibilities to separate methods.
public class MyBLClass()
{
public void MyBLMethod(int userId)
{
using (IMyContext entities = GetContext())
{
User user = GetUserFromDb(entities, userId);
// Some BL Code here
}
}
protected virtual IMyContext GetContext()
{
return new MyDbContext();
}
protected virtual User GetUserFromDb(IMyDbContext entities, int userId)
{
return entities.Users.Find(userId);
}
}
Now unit testing business logic should be piece of cake because your unit test can inherit your class and fake context factory method and query execution method and become fully independent on EF.
// NUnit unit test
[TestFixture]
public class MyBLClassTest : MyBLClass
{
private class FakeContext : IMyContext
{
// Create just empty implementation of context interface
}
private User _testUser;
[Test]
public void MyBLMethod_DoSomething()
{
// Test setup
int id = 10;
_testUser = new User
{
Id = id,
// rest is your expected test data - that is what faking is about
// faked method returns simply data your test method expects
};
// Execution of method under test
MyBLMethod(id);
// Test validation
// Assert something you expect to happen on _testUser instance
// inside MyBLMethod
}
protected override IMyContext GetContext()
{
return new FakeContext();
}
protected override User GetUserFromDb(IMyContext context, int userId)
{
return _testUser.Id == userId ? _testUser : null;
}
}
As you add more methods and your application grows you will refactor those query execution methods and context factory method to separate classes to follow single responsibility on classes as well - you will get context factory and either some query provider or in some cases repository (but that repository will never return IQueryable or get Expression as parameter in any of its methods). This will also allow you following DRY principle where your context creation and most commonly used queries will be defined only once on one central place.
So at the end you can have something like this:
public class MyBLClass()
{
private IContextFactory _contextFactory;
private IUserQueryProvider _userProvider;
public MyBLClass(IContextFactory contextFactory, IUserQueryProvider userProvider)
{
_contextFactory = contextFactory;
_userProvider = userProvider;
}
public void MyBLMethod(int userId)
{
using (IMyContext entities = _contextFactory.GetContext())
{
User user = _userProvider.GetSingle(entities, userId);
// Some BL Code here
}
}
}
Where those interfaces will look like:
public interface IContextFactory
{
IMyContext GetContext();
}
public class MyContextFactory : IContextFactory
{
public IMyContext GetContext()
{
// Here belongs any logic necessary to create context
// If you for example want to cache context per HTTP request
// you can implement logic here.
return new MyDbContext();
}
}
and
public interface IUserQueryProvider
{
User GetUser(int userId);
// Any other reusable queries for user entities
// Non of queries returns IQueryable or accepts Expression as parameter
// For example: IEnumerable<User> GetActiveUsers();
}
public class MyUserQueryProvider : IUserQueryProvider
{
public User GetUser(IMyContext context, int userId)
{
return context.Users.Find(userId);
}
// Implementation of other queries
// Only inside query implementations you can use extension methods on IQueryable
}
Your test will now only use fakes for context factory and query provider.
// NUnit + Moq unit test
[TestFixture]
public class MyBLClassTest
{
private class FakeContext : IMyContext
{
// Create just empty implementation of context interface
}
[Test]
public void MyBLMethod_DoSomething()
{
// Test setup
int id = 10;
var user = new User
{
Id = id,
// rest is your expected test data - that is what faking is about
// faked method returns simply data your test method expects
};
var contextFactory = new Mock<IContextFactory>();
contextFactory.Setup(f => f.GetContext()).Returns(new FakeContext());
var queryProvider = new Mock<IUserQueryProvider>();
queryProvider.Setup(f => f.GetUser(It.IsAny<IContextFactory>(), id)).Returns(user);
// Execution of method under test
var myBLClass = new MyBLClass(contextFactory.Object, queryProvider.Object);
myBLClass.MyBLMethod(id);
// Test validation
// Assert something you expect to happen on user instance
// inside MyBLMethod
}
}
It would be little bit different in case of repository which should have reference to context passed to its constructor prior to injecting it to your business class.
Your business class can still define some queries which are never use in any other classes - those queries are most probably part of its logic. You can also use extension methods to define some reusable part of queries but you must always use those extension methods outside of your core business logic which you want to unit test (either in query execution methods or in query provider / repository). That will allow you easy faking query provider or query execution methods.
I saw your previous question and thought about writing a blog post about that topic but the core of my opinion about testing with EF is in this answer.
Edit:
Repository is different topic which doesn't relate to your original question. Specific repository is still valid pattern. We are not against repositories, we are against generic repositories because they don't provide any additional features and don't solve any problem.
The problem is that repository alone doesn't solve anything. There are three patterns which have to be used together to form proper abstraction: Repository, Unit of Work and Specifications. All three are already available in EF: DbSet / ObjectSet as repositories, DbContext / ObjectContext as Unit of works and Linq to Entities as specifications. The main problem with custom implementation of generic repositories mentioned everywhere is that they replace only repository and unit of work with custom implementation but still depend on original specifications => abstraction is incomplete and it is leaking in tests where faked repository behaves in the same way as faked set / context.
The main disadvantage of my query provider is explicit method for any query you will need to execute. In case of repository you will not have such methods you will have just few methods accepting specification (but again those specifications should be defined in DRY principle) which will build query filtering conditions, ordering etc.
public interface IUserRepository
{
User Find(int userId);
IEnumerable<User> FindAll(ISpecification spec);
}
The discussion of this topic is far beyond the scope of this question and it requires you to do some self study.
Btw. mocking and faking has different purpose - you fake a call if you need to get testing data from method in the dependency and you mock the call if you need to assert that method on dependency was called with expected arguments.

MEF and IObservables

I have a singleton IObservable that returns the results of a Linq query. I have another class that listens to the IObservable to structure a message. That class is Exported through MEF, and I can import it and get asynchronous results from the Linq query.
My problem is that after initial composition takes place, I don't get any renotification on changes when the data supplied to the Linq query changes. I implemented INotifyPropertyChanged on the singleton, thinking it word make the exported class requery for a new IObservable, but this doesn't happen.
Maybe I'm not understanding something about the lifetime of MEF containers, or about property notification. I'd appreciate any help.
Below are the singleton and the exported class. I've left out some pieces of code that can be inferred, like the PropertyChanged event handlers and such. Suffice to say, that does work when the underlying Session data changes. The singleton raises a change event for UsersInCurrentSystem, but there is never any request for a new IObservable from the UsersInCurrentSystem property.
public class SingletonObserver: INotifyPropertyChanged
{
private static readonly SingletonObserver _instance = new SingletonObserver();
static SingletonObserver() { }
private SingletonObserver()
{
Session.ObserveProperty(xx => xx.CurrentSystem, true)
.Subscribe(x =>
{
this.RaisePropertyChanged(() => this.UsersInCurrentSystem);
});
}
public static SingletonObserverInstance { get { return _instance; } }
public IObservable<User> UsersInCurrentSystem
{
get
{
var x = from user in Session.CurrentSystem.Users
select user;
return x.ToObservable();
}
}
}
[Export]
public class UserStatus : INotifyPropertyChanged
{
private string _data = string.Empty;
public UserStatus
{
SingletonObserver.Instance.UsersInCurrentSystem.Subscribe(sender =>
{
//set _data according to information in sender
//raise PropertyChanged for Data
}
}
public string Data
{
get { return _data; } }
}
}
My problem is that after initial composition takes place, I don't get any renotification on changes when the data supplied to the Linq query changes.
By default MEF will only compose parts once. When a part has been composed, the same instance will be supplied to all imports. The part will not be recreated unless you explicitly do so.
In your case, if the data of a part change, even if it implements INotifyPropertyChanged, MEF will not create a new one, and you don't need to anyway.
I implemented INotifyPropertyChanged on the singleton, thinking it word make the exported class requery for a new IObservable
No.
Maybe I'm not understanding something about the lifetime of MEF containers, or about property notification.
Property notification allows you to react to a change in the property and has no direct effect on MEF. As for the container's lifetime, it will remain active until it is disposed. While it is still active, the container will keep references to it's compose parts. It's actually a little more complex than that, as parts can have different CreationPolicy that affects how MEF holds the part, I refer you to the following page: Parts Lifetime for more information.
MEF does allow for something called Recomposition. You can set it likewise:
[Import(AllowRecomposition=true)]
What this does tough is allow MEF to recompose parts when new parts are available or existing parts aren't available anymore. From what I understand it isn't what you are referring to in your question.

Adding views does not call MEF Import statements

I have a view controlled by a view model (using MEF) that allows a user to selected items from a drop down list. Each item that the user selects populates a tab control that is defined as a region. The view model instantiates a view, assigns it a view model, then adds it to the region:
ProjectDetailView view = new ProjectDetailView();
ProjectDetailViewModel viewModel = new ProjectDetailViewModel();
viewModel.CurrentProject = project;
view.DataContext = viewModel;
RegionManager.Regions["SelectedItemsRegion"].Add(view);
This all works fine from the UI perspective. The project detail view model, however, has [Import] statements on it to receive an EventAggregator for publishing events.
[Import]
public IEventAggregator EventAggregator { get; set; }
Because I'm only adding views to a region and not doing a request navigate to a specific URI, the composition never occurs (or at least it doesn't appear to) so EventAggregator is always null. How do I get these dynamically added views to go through the process of importing the requested classes? Is there a compose method I can call on a specific view so things get resolved?
I would suggest that you create a factory class to instantiate EventAggregator, like so:
public EventAggregatorFactory
{
[Export(typeof(IEventAggregator))]
public IEventAggregator Instance
{
get
{
return new EventAggregator();
}
}
}
Obviously, move the Export declaration into the factory class. This should allow proper instantiation of the Import of EventAggregator when the viewmodel is invoked.