I'm fairly new to the whole n-tier architecture thing, and I had some questions about using MVVM with a 3-tier application.
From my understanding, we have:
The View, or UI layer, which is the xaml file
The Model, which is a custom class containing properties and methods that "models" the data object
The ViewModel, which is the "adapter" between the View and the Model
A WCF Server which is supposed to handle Database Access among other things
SQL Database for storing data
My question is, how do I put this all together using the Data Access Layer? With MVVM, I would have the models contain the methods to Load/Update themselves. Instead should this be something that happens on the WCF Server? If so, should the reference to the server be stored in the Model or the ViewModel? And how should it be called?
Strictly, DAL is not a part of MVVM pattern. DAL is somewhere 'behind' model, and view and view model should know nothing about DAL.
For example, expose entities as properties of your model which are loaded at first access.
public class ProductListModel
{
public List<Product> AllProducts
{
get
{
if (_AllProducts == null)
_AllProducts = MyServiceProxy.LoadAllProducts(...)
return _AllProducts;
}
}
public void SaveChanges()
{
if (_AllProducts != null)
MyServiceProxy.SaveProducts(AllProducts);
}
}
Data Access is a separate and independant issue... You can implement it in a number of different ways and patterns, but in all cases, the end result is a model that will be used by your MVVM classes.
The WCF may return the classes used in your model, or it may return simpler classses that are designed just as data transfer objects, in which cxase you will have transform these objects into instances of the classes defined in your model...
Actual data access (to-from the DataBase itself is of course coded on the server side of the WCF...
There are tons of very lengthy blog posts and descriptions on organizing all this. Here is the one I read most recently (today):
[link text][1]
[1]: http://dotnetslackers.com/articles/data-management/About-layers-separation-and-Entity-Framework.aspx "Dino Esposito on EF and Layers
Related
I think I'm on my way to finally grokking MVVM. I was just looking at a situation I found myself in and I'm wondering if I should combine two of my layers. I currently have a structure like this:
Domain models (in a separate .net project)
WPF-side "models" which wrap domain models and track dirty state
WPF ViewModels
Views
The question is whether I should combine 2 and 3. Right now #2 is the layer that gets passed around by my mediator to facilitate all the viewmodels knowing what document is currently opened. But I think my code for 2 and 3 is too similar and is unnecessary duplication at this point.
Example:
// in layer 2, class ProjectDocument
// Project is an instance of the domain model
public string Name
{
get { return Project.Name; }
set
{
if (Project.Name == value) return;
Project.Name = value;
Dirty = true;
}
}
// in layer 3, class ProjectSettingsViewModel
// _project is a ProjectDocument
public string Name
{
get { return _project.Name; }
set
{
_project.Name = value;
OnPropertyChanged("Name");
}
}
Seeing that struck me as unnecessary. So should I combine them? On one hand, it would remove a lot of redundant code and I'd have fewer places to update when I change things. On the other, I might be giving one class too much responsibility, and also it seems inappropriate for an actual ViewModel to be passed around to other VMs via my mediator. The ProjectSettingsViewModel wouldn't use even half of the fields on ProjectDocument if they were combined.
Maybe I'm looking at this the wrong way. Is there a better way to reduce the duplication while still keeping the responsibilities separate?
I have a master viewmodel that handles application states like which document/tab/window is open and I have an ISettingssService for other global needs. Passing one viewmodel to another is discouraged and you might want to think about creating am iSettings service that can be injected into the viewmodels, then the viewmodels can interact with "global" settings but the viewmodels are still decoupled because they do not depend on another viewmodel.
So, I would not combine them. Either I would have a dictionary of documents that can be open in the master viewmodel with a current open doc property or move this logic to a service/interface that gets used by each viewmodel.
Hope this helps.
I want to build a basic wpf/mvvm application which gets the data from a server with WCF and allows the client to display/manipulate (with CRUD operations) this data.
So far, I thought about something like that for the architecture :
a "global" model layer, which implements validation, research criterias, and INotifyPropertyChanged and services contracts
some services layers, by mainly one for entity framework 4, implementing the contracts of the model layer and allowing me to access and manipulate data.
Note that I want to have an offline datasource as well, say XML or something else, and thus another service (I plan on using some DI/IoC)
the WCF layer
Extra layer for data storing client side ?
the ViewModel
I'm clear on the Views/ViewModel part, but I have troubles figuring out the relations between the model, WCF and the viewmodel.
My questions are :
How should I handle the model generated by EF ? Get rid of it and go
for a code first approach, manually doing the mapping with the
database ?
For the WCF data transport, should I have relational
properties in my model, i.e a Product has a Customer instead of a
CustomerId ?
Should I have an additional layer between the WCF and
the ViewModel, for storing and manipulating data or is it a best
practice to directly plug the ViewModel into the WCF ?
Any other tips for this kind of architecture are welcome...
There are different solutions for the architecture of a 3-tier WPF application, but here is one possibility:
1+2) One solution is to create "intermediate" objects that represent what your client application actually needs.
For instance, if your application needs to display information about a product plus the associated customer name, you could build the following object:
public MyProduct
{
// Properties of the product itself
public int ProductID { get; set; }
public string ProductName { get; set; }
...
// Properties that come from the Customer entity
public string CustomerName { get; set; }
}
You can then expose a stateless WCF service that returns your product from an ID:
[ServiceContract]
MyProduct GetProductByID(int productID);
In the server side of your application (i.e. the implementation of your service), you can return a MyProduct instance build by querying the database through EF (one context per call):
public MyProduct GetProductByID(int productID)
{
using (DBContext ctx = new ....)
{
return from p in ctx.Products
where p.ID == productID
select new MyProduct
{
ProductID = p.ID,
ProductName = p.Name,
CustomerName = p.Customer.Name // Inner join here
};
}
}
3) Adding additional layer between the WCF services and the ViewModel might be considered as over-engineering. IMHO it's OK to call WCF services directly from the ViewModel. WCF generated client proxy code has the actual role of your model (at least one part of your model).
EDIT:
why MyProduct should reference the CustomerName instead of the
Customer.In my case, Customer would have many properties I'd work
with. Woudn't this "mapping" be too expensive ?
You can use the actual entities. But on client side, as it's a 3-tier architecture, you have no access to the DB through the navigation properties. If there was a nested Customer property (of type Customer), the client would have access to theProduct.Customer.Products, which has no sense has you can't lazy load entities this way (no DB context on client side).
Flattened "intermediate" POCOs are much more simple IMO. There is no performance issues, the mapping is straightforward and the CPU usage for this particular operation is infinitesimal compared to the DB request time.
First of all, some general information: there is a really good tutorial on MVVM by Jason Dollinger available at Lab49
edit
The video covers most of the needs when architecting a WPF application.
Dependency injection and the connection to WCF are also covered (but
not in depth when speaking about WCF, but with a really strong way
to come up with good solutions here)
The source code he developed is also available here
In my opinion, everybody who has to do with MVVM should see it!
=> 1. How should I handle the model generated by EF ? Get rid of it and go for a code first approach, manually doing the mapping with the database ?
AutoMapper can help here. Codeplex of AutoMapper
Your issue seems like a perfect fit for this!
=> 2. For the WCF data transport, should I have relational properties in my model, i.e a Product has a Customer instead of a CustomerId ?
Don't mess with the model! A productid is part of orders, and orders have a customer-id.
Stick to this. In your service layer, you will probably end up with ids anyway.
Since you probably do not alter products nor customers here. If you do (and my
orders example does not fit then), you can transport the dynamic data, not the static.
=> 3. Should I have an additional layer between the WCF and the ViewModel, for storing and manipulating data or is it a best practice to directly plug the ViewModel into the WCF ?
In most cases, I have a service layer with gets injected into my viewmodel in the constructor.
That can be assumed another layer, as it handles the WCF client part and
handles the "changed" events of the server side. (row changed, new row, row deleted etc)
edit
If you have to dispatch your service layer events, it is much easier to have
that small, leightweight layer between WCF and ViewModel. As soon as you have
to, you will probably come up with such a layer naturally.
I am working on a Prism desktop application and would like to know the best way to deal with lookup / reference data lists when using a WCF backend. I think this question may cover a few areas and I would appreciate some guidance
For example, consider a lookup that contains Products(codes and descriptions) which would be used in a lot of different input screens in the system.
Does the viewmodel call the WCF service directly to obtain the data to fill the control?
Would you create a control that solely deals with Products with its own viewmodel etc and then use that in every place that needs a product lookup or would you re-implements say a combobox that repopulates the products ItemsSource in every single form view model that uses it?
Would I create a brand new WCF service called something like LookupData service and use that to populate my lookup lists? - I am concerned I will end up with lots of lookups if I do this.
What other approaches are there for going about this?
I suggest creating your lookup object/component as a proxy object for WCF service. It can work in several ways, but most simple coming to my mind would be:
Implement WCF service with methods to provide all Products entities and requested one (eg. basing on product code)
Implement component that will use WCF client to get products, let's call it ProductsProvider
Your view models will take dependency on ProductsProvider (eg. via constructor injection)
Key element in this model is ProductsProvider - it will work as kind of cache for Products objects. First, it will ask web service for all products (or some part of it, up to your liking) to start with. Then, whenever you need to lookup product, you ask provider - it's provider's responsibility to deal with how product should be looked up - maybe it's already in local list? Maybe it will need to call web service for update? Example:
public class ProductsProvider
{
private IList<Product> products;
private IProductsService serviceClient;
public ProductsProvider(IProductsService serviceClient)
{
this.serviceClient = serviceClient;
this.products = serviceClient.GetAllProducts();
}
public Product LookUpProduct(string code)
{
// 1: check if our local list contains product with given code
// 2: if it does not, call this.serviceClient.LookUpProduct
// 3: if service also doesn't know such product:
// throw, return null, report error
}
}
Now, what this gives you is:
you only need to have one ProductsProvider instance
better flexibility with when and how your service is called
your view models won't have to deal with WCF at all
Edit:
As for your second question. Control may not be needed, but having view model for Product entity is definitely a good idea.
Is it possible to have a single implementation of business logic layer (based on CSLA) and consume it from different presentation technoligies like winform, silverlight etc. There exists CSLA for silverlight. Does that mean implementing and maintaining different BLL for different presentation technologies.
Any help would be appreciated.
This is very easy todo with the CodeSmith CSLA templates. We have a PetShop Silverlight MVVM and Web sample application located here that shows off the generated code.
Thanks
-Blake Niemyjski (Author of the CodeSmith CSLA Templates)
This is very possible with CSLA. The main difference with using your BLL with different UI technologies is the use of the Begin & Callback mechanism of data portal calls in CSLA for Silverlight. If you use this mechanism for all your UI technologies, this would allow you to use the same BLL.
I would suggest that you use separate Factory objects for your BLL so you can decide when to use the BeginInvoke & Callback mechanism and your business objects would be untouched.
You could also create duplicate factory methods if you felt that was necessary. For example if you had a business object of Customer:
public class Customer : Csla.BusinessBase<Customer>
{
private Customer() { }
private void DataPortal_Fetch(SingleCriteria<Customer, int> criteria)
{ // populate here }
}
Then you could have a CustomerFactory object that contained both methods for Silverlight and the other UI technologies:
public static class CustomerFactory
{
// Handle most UI needs
public static Customer Fetch(int id)
{
return DataPortal.Fetch<Customer>(new SingleCriteria<Customer, int>(id));
}
// Handle Silverlight needs
public static void Fetch(int id)
{
DataPortal.BeginFetch<Customer>(id, FetchCallback);
}
private static FetchCallback(object sender, DataPortalResult<Customer> result)
{
// notify the UI of result.Object
}
}
You could also get a little more clever and implement dependency injection via an IoC container to make the call to your factory methods a little more smart.
The bottom line is that your actual business objects will not change but your factory objects may have duplicate CRUD methods in certain circumstances.
Rocky actually has a sample (ProjectTracker) that implements a single BLL with multiple UI layers at his web site (listed under 'Samples' at http://www.lhotka.net/cslanet/Download.aspx)
I read this article today http://dotnetslackers.com/articles/silverlight/Silverlight-3-and-the-Data-Form-Control-part-I.aspx about the use of the MVVM pattern within a silverlight app where you have your domain entities and view spesific entities which basically is a subset of the real entity objects. Isn't this a clear violation of the DRY principle? and if so how can you deal with it in a nice way?
Personally, I don't like what Dino's doing there and I wouldn't approach the problem the same way. I usually think of a VM as a filtered, grouped and sorted collections of Model classes. A VM to me is a direct mapping to the View, so I might create a NewOrderViewModel class that has multiple CollectionViews used by the View (maybe one CV for Customers and another CV for Products, probably both filtered). Creating an entirely new VM class for every class in the Model does violate DRY in my opinion. I would rather use derivation or partial classes to augment the Model where necessary, adding in View specific (often calculated) properties. IMO .NET RIA Services is an excellent implementation of combining M and VM data with the added bonus that it's usable in on both the client and the server. Dino's a brilliant guy, but way to call him out on this one.
DRY is a principle, not a hard rule. You are a human and can differentiate.
E.g. If DRY really was a hard rule you would never assign the same value to two different variables. I guess in any non trivial program you would have more than one variable containing the value 0.
Generally speaking: DRY does usually not apply to data. Those view specific entities would probably only be data transfer objects without any noteworthy logic. Data may be duplicated for all kinds of reasons.
I think the answer really depends on what you feel should be in the ViewModel. For me the ViewModel represents the model of the screen currently being displayed.
So for something like a ViewCategoryViewModel, I don't have a duplication of the fields in Category. I expose a Category object as a property on the ViewModel (under say "SelectedCategory"), any other data the view needs to display and the Commands that screen can take.
There will always be some similarity between the domain model and the view model, but it all comes down to how you choose to create the ViewModel.
It's the same as with Data Transfer Objects (DTO).
The domain for those two object types is different, so it's not a violation of DRY.
Consider the following example:
class Customer
{
public int Age
}
And a corsponding view model:
class CustomerViewModel
{
public string Age;
// WPF validation code is going to be a bit more complicated:
public bool IsValid()
{
return string.IsNullOrEmpty(Age) == false;
}
}
Differnt domains - differnet property types - different objects.