I'm using Caliburn and C#, but I feel like this is a generic MVVM/DI question.
Let's say I have a view model, NoteViewModel, that is passed a model object called Note.
Here is some code:
class NoteViewModel : PropertyChangedBase
{
private readonly Note _note;
public NoteViewModel(Note note)
{
_note = note;
}
public string Title
{
get { return _note.Title; }
set { _note.Title = value; NotifyOfPropertyChange(() => Title); }
}
}
Right now this object is created by calling new() and passing a model object.
Well, that works great, but now I need to add a method that requires an imported class from my DI container.
So do I merely call ServiceLocator.Current.GetInstance() to get it? Or should I design this view model to be created via the DI container and somehow setup a way to pass a Note object?
What is the proper way to design this view model? Basically a "PerInstance" view model that requires a model object for it's use. Does Caliburn have a built-in way to do this?
Caliburn has an interface (IHaveSubject and its typed version IHaveSubject) addressing this kind of scenario: basically it allows a mean to configure the ViewModel with a "subject" after its instantiation, tipically through the container:
class NoteViewModel : PropertyChangedBase, IHasSubject<Note> {
...
}
myNoteViewModel = ... //obtain an instance
myNoteViewModel.WithSubject(new Note());
This solution also integrates well with ISubjectSpecification / Conductor
infrastructure.
Even though post-construction initialization is a simple and effective solution, you may not want (from a pure design perspective) to renounce to an explicit constructor parameter to enforce the need for a Note to istantiate the ViewModel.
In this case I think you have to leverage peculiar features of your DI container, because you may have some parameters of the constructor representing a "real" input parameter, while other may be service dependencies.
Castle Windsor, for example, has a nice feature allowing you to quickly build an explicit (typed) factory for your ViewModel; the factory method will only allow to set the "real" parameters, while all dependencies are managed by the container (see this post for an extensive description of this Windsor feature: http://kozmic.pl/archive/2009/12/24/castle-typed-factory-facility-reborn.aspx)
Can you solve it using hierarchical view models?
To me it becomes more and more clear that I need one ViewModel per View and one ViewModel per model item or collection when building larger application.
That way we can build up ViewModels hierarchically, matching the XAML hierarchy.
The required objects can be defined or injected at the top level by app's main view model then. The nested view models can then access anything the way you design it to make things reachable by them.
About Caliburn, I don't know any specific things about that framework, sorry.
I'm using the ServiceLocator also. And I also "feel dirty" in doing this. But I have resolved to use the YAGNI principle and keep this pattern until I find a compelling payback to the complexity of adding 5 IServices into my constructors, passing them up via 3-4 layers of inheritance to the base classes in which they are needed, and creating everything via the container. Of course my app is evolving, and YAGNI doesn't always last...
Related
I am currently developing a UWP application, but I think this question applies to any project type with a UI. I have built a View Model for my UI using the new Microsoft Toolkit MVVM library. It has properties such as:
private bool _isLoginAvailable = true;
public bool IsLoginAvailable
{
get => _isLoginAvailable;
set => SetProperty(ref _isLoginAvailable, value);
}
Furthermore, I have a few business methods that as parameters require up to 5-6 of these properties.
Reading on forums, I saw that it is unadvised to business logic within the view model, therefore, I came up with the following options:
Create a new class for the methods, and use the view model as a parameter: SampleMethod(SampleViewModel vm). Then, if I create an object of this class in the view model, I could use SampleMethod(this). At this point, I don't really see a difference between this option, and including the method within the view model class.
Second option I see is to add each required parameter to the method, and return each parameter as well in a tuple: SampleMethod(var1, var2, var3...) { return (var1, var2, var3...)} This to me seems very cumbersome.
The third option I figured is to use the MVVM Toolkit's messaging feature. In this case, I can set up the constructor of the view model to listen to messages with Messenger.Register<SampleViewModel, Var1Message>(this, (r, m) => r.var1 = m.Value);. Then, the method in a differenct class can send the value in message using Messenger.Send(new Var1Message(message). While this seems to be the best option, as it can be easily implemented together with dependency injection, it quickly becomes very convoluted, as for each property a new sealed class is required, that describes the message.
Is any of these options the best practice, or is there an option that I am not aware of?
If business methods require multiple properties in your VM, then maybe the properties should be in the business object? Are the properties intrinsic to the business rules, or do they only exist in the context of the view?
VM properties can just pass through to the business properties, or quite often you can just directly expose the business object itself in your VM.
Why do you think that its inadvisable to use methods within a ViewModel?
A ViewModel must act as an intermediary between the View, Model and business logic classes or libraries.
Consider using a RelayCommand (implement the property as ICommand type) in your ViewModel, this can be bound to a button click and is used to call a method within your ViewModel that takes the property values and passes them to your business logic.
A typical scenario for a ViewModel may be user input on a form, with your ViewModel properties being bound by the View. The user then clicks a button to submit this data.
The application I'm trying to get to work uses MVVM. The biggest part of this post is an explanation of what I tried and what I got working. The question is near the bottom of the post. The used Localizer class is only used here as an example and can easily be replaced with another class.
I have a class library with a Localizer class. This purpose of this class is to change the language of the application on the fly, without having to restart the application. The `Localizer has to be instantiated before it can be used but once instantiated, should be usable in the entire application. (The class uses the application resources to localize the application.)
My first approach I could think of is making the Localizer a public static class with a public static void Initialize method. This way I could initialize the Localizer like this
Localizer.Initialize(/* Needed arguments here */);
on the application level and use it wherever I want in either my class library or application like this
string example = Localizer.GetString(/* A key in the resource dictionary */);
Considering the class library is written by me (only I have the source code) and used by other people who have no clue about the source code (they only know what the class library can do), I would have to explicitly state in some sort of "How to use this class library" that they need to call Localizer.Initialize on the application level in order to use it everywhere in their application.
After doing some research a lot of people state that this is a bad practice and suggest investigating what Dependency Injection (DI) and Inversion of Control (IoC), so I did. I learned that DI is doing about the same as my first approach but remove the static stuff, use Localizer.Initialize as the constructor and inject the instantiated class in my other classes.
So the second approach is dependency injection and this is where I'm stuck. I managed to let my application compile with a single MainWindowView and MainWindowViewModel with the following code:
protected override void OnStartup(StartupEventArgs e)
{
ILocalizer localizer = new Localizer(Current.Resources, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name, "Languages", "Language", "en");
var mainWindowViewModel = new MainWindowViewModel(localizer);
var mainWindowView = new MainWindowView { DataContext = mainWindowViewModel };
mainWindowView.Show();
base.OnStartup(e);
}
What the above code does is, is inject the localizer into MainWindowViewModel. This way no additional code is added to the MainWindowView code behind and has the view a view model bound to.
In MainWindowViewModel the constructor is like this (note that the message box is called somewhere else but was moved here to minimize the code):
ILocalizer _localizer;
public MainWindowViewModel( ILocalizer localizer)
{
_localizer = localizer;
MessageBox.Show(_localizer.GetString(/* A key in the resource dictionary */));
}
The above code is still compiling and running fine without exceptions. The problem occurs when I have either UserControls in my class library with a view and view model that also require the localizer instance.
I think I have a solution for when I have a UserControl in my application assembly but it feels like it is more 'complex' then when I would use a static class. I usually just bind the view model of a UserControl to the view in its code behind. This way I can simply add the UserControl to my .xaml code like this <local:UserControl1 /> without a lot of extra hustle. This way the view model parent view model doesn't have to be concerned about child view models.
With DI I would do something like this in my parent (the child would be the same as in the previous block of code):
View
<n:UserControl1 DataContext="{Binding UC1ViewModel}" />
ViewModel
public UserControl1ViewModel UC1ViewModel { get; set; }
ILocalizer _localizer;
public MainWindowViewModel(ILocalizer localizer)
{
_localizer = localizer;
UC1ViewModel = new UserControl1ViewModel(localizer);
}
The above is still all working fine, no problems so far. The only thing that changed is that the DataContext is set in the parents view and the content of the DataContext is set in the view model of the parent.
The question
I also have several UserControls in my class library. These can be used by the users of the class library but they can't alter them. Most of these UserControls are some fixed pages that display information about a person, car, etc. The intention is that, for example the label with the name of the person is "Name" in English, "Naam" in Dutch, etc. (which are all declared in the view and are working fine) but there is also text in the code behind that has to be localized and this is where I'm stuck.
Should I approach the problem the same way as I'm doing with a UserControl in my applications assembly? This feels really counterproductive if let say 20+ of these UserControls are used in a single parent view.
I also feel that I'm not implementing DI 100% correctly.
Problem
DI is not as simple as you've made it look. There are DI frameworks out there which take care of the DI concern, and they are mature pieces of software.
You can't really do DI yourself without designing a DI container because of the way DI should work
DI solves a few problems, a couple of the main ones are:
IoC - ensuring that components aren't tightly coupled by moving the resolution and provision of dependencies outside of the component classes
Lifetime scope - ensures that components have a well defined lifetime/lifecycle and that they are correctly instantiated and disposed of at key points in your application
How does it look?
You shouldn't even see the container! - you should only see components dependencies and the rest should look like magic...
DI containers should be very transparent. Your components and services should require their dependencies simply by specifying what the dependencies are (in their constructors)
What's my current problem?
You don't want to be having to manually wire up sub-dependencies with code like this:
public MainWindowViewModel(ILocalizer localizer)
{
_localizer = localizer;
UC1ViewModel = new UserControl1ViewModel(localizer); // <-- ouch
}
There are a number of problems with the above:
You are making the MainWindowViewModel responsible for creating the UC1ViewModel and managing the lifetime of the object (this isn't always a bad thing as sometimes you want to manage the lifetime of an object in a particular component)
You are coupling the implementation of the MainWindowViewModel to the constructor implementation of UserControl1ViewModel - if you require another dependency in UserControl1ViewModel, suddenly you have to update MainWindowViewModel to inject that dependency, cue a lot of refactoring. This is because you are instantiating the type yourself instead of letting a container do it.
How do containers prevent code like the above?
With any container you should be registering components
The container will track the list of possible components and services and use this registry to resolve dependencies.
It also tracks the dependencies lifecycle (singleton, instanced etc)
Ok I've registered everything, what next?
Once you have registered all your dependencies, you then resolve your root component from the container. This is known as the composition root and should be the 'entry point' for your application (usually the main view or main method).
The container should take care of wiring up and creating the dependencies for everything that stems from that composition root.
Example:
(Pseudo code)
public class ApplicationBootstrapper
{
private IContainer _container;
public ApplicationBootstrapper() {
_container = new SomeDIContainer();
_container.Register<SomeComponent>().AsSingleton(); // Singleton instance, same instance for every resolve
_container.Register<SomeOtherComponent>().AsTransient(); // New instance per resolve
// ... more registration code for all your components
// most containers have a convention based registration
// system e.g. _container.Register().Classes().BasedOn<ViewModelBase> etc
var appRoot = _container.Resolve<MainWindowViewModel>();
appRoot.ShowWindow();
}
}
Now when your application runs, all dependencies are injected into the root and all dependencies of the root and so on
Your MainWindowViewModel could then specify a dependency on the UC as such:
public MainWindowViewModel(UC1ViewModel vm)
{
}
Notice how the MainWindowViewModel no longer needs an ILocalizer instance, it will be resolved and injected into the UC1ViewModel for you (unless of course you need it).
Couple of points to note
You should not pass an instance of the container around. If you are referencing the container in your application code anywhere other than during application startup you are probably doing something wrong
Deferred resolution of dependencies is usually achieved with factories (types that are designed specifically to resolve from the container on behalf of your components). The factory should be injected into the component and the component can then call the factory to get the instance it needs. This also allows you to pass arguments to the dependency.
Use SOLID principles, depend on abstractions not concrete classes. This way it's much easier to swap out components if you decide to change the way something works (you just change the registration code to use a different concrete class that implements the same interface, et voila, no refactoring the app)
Anything else
This is by no means a concise view of DI, there is a lot to consider, but hopefully it will get you started. As Steven mentioned, if you are planning on redistributing the library you should read up on best practices.
The original post on dos/dont's is here:
Dependency Inject (DI) "friendly" library
Which DI container should you use?
The world is your oyster. I'm a fan of Castle Windsor - it's not the fastest (I can't think of an app I've written where I've ever needed component resolution to be ninja fast...), but it's certainly fully featured.
Update: couple of non queries I didn't really address
Plugins
Castle Windsor has plugin capabilities built in - so you can drop a DLL into your application directory which adds functionality to your application by registering components with the container. Not sure if this applies to your UC class library or not (you could just make the app depend on it unless it needs to actually be a plugin)
Other stuff
There are also quite a lot of MVVM frameworks with several different approaches on view/viewmodel resolution (viewmodel-first, view-first, hybrid approaches).
You may want to consider using one of these to help guide you in structuring your application if you are not already using one (it doesn't sound like you are).
Have a look at this article on localization in WPF applications:
http://www.codeproject.com/Articles/299436/WPF-Localization-for-Dummies
Your localization can be handled via resource assemblies for each language you need to support and the correct one will be used at run-time based on the current culture - or a fallback culture. Your view models can reference the resources and shouldn't care about the specific locale.
I am writing my first WPF application and I would like to ask you for help with a problem that I encountered.
I am trying to follow the MVVM pattern and I came to a point where I need to implement modal dialogs. I googled/read on the topic for some time and I was able to settle on a solution. However, when refactoring I encountered a dilemma that concerns using a DI (constructor injection) as a replacement of a service locator.
I am going to be referencing these: http://pastebin.com/S6xNjtWW.
I really like the approach of Roboblob:
First: He creates an abstraction of a modal dialog (interface). I named the interface IModalDialog and this is how it looks like:
public interface IModalDialog
{
bool? DialogResult { get; set; }
object DataContext { get; set; }
void Show();
bool? ShowDialog();
void Close();
event EventHandler Closed;
}
Second: An abstraction of modal dialog service:
public interface IModalDialogService
{
void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel, Action<TDialogViewModel> onDialogClose) where TDialogViewModel : class;
void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel) where TDialogViewModel : class;
}
Third: The concrete implementation of IModalDialogService:
public class ModalDialogService : IModalDialogService
{
public void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel, Action<TDialogViewModel> onDialogClose) where TDialogViewModel : class
{
// set datacontext
if (viewModel != null)
{
view.DataContext = viewModel;
}
((System.Windows.Window)view).Owner = System.Windows.Application.Current.MainWindow;
// register
if (onDialogClose != null)
{
view.Closed += (sender, e) => onDialogClose(viewModel);
}
view.ShowDialog();
}
public void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel) where TDialogViewModel : class
{
this.ShowDialog(view, viewModel, null);
}
Fourth: There are more implementations of IModalDialog. Each is a Window-derived class that implements IModalDialog.
Before I ask the question (describe the problem), I need to explain this beforehand:
Let's say that I have some more services, like for example IMessageBoxService.
Then I need to declare these dependencies in the constructor of MainWindowViewModel:
public MainWindowViewModel(IModalDialogService a,
IMessageBoxService b,
...)
so that I can inject them (either by hand or using IOC container like Unity, etc.).
In order to be able to use the modal dialog service there is one missing piece of puzzle - the ability to resolve a concrete implementation of IModalDialog based on some key.
Roboblob in his article solves this last piece of puzzle using a ServiceLocator pattern:
public class Bootstrapper
{
public static void InitializeIoc()
{
SimpleServiceLocator.SetServiceLocatorProvider(new UnityServiceLocator());
SimpleServiceLocator.Instance.Register<IModalDialogService, ModalDialogService>();
SimpleServiceLocator.Instance.Register<IMessageBoxService, MessageBoxService>();
...
SimpleServiceLocator.Instance.Register<IModalWindow, EditUserModalDialogView>(Constants.EditUserModalDialog);
}
}
so he inside his MainWindowViewModel simply calls the static classes Get and resolves a concrete implementation of IModalDialog window based on a key.
Even Josh Smith uses a similar approach in his article but in comments he says that (DI - constructor injection) is a valid option.
The referenced StackOverflow answer also describes a similar WindowViewLoaderService that could be modified and use.
So the question is - what would be the best way to replace the ServiceLocator (which resolves the concrete implementations of IModalDialog) with a dependency injection?
My train of thoughts was:
One possibility is (due to the project not being very big/developed by me only) to just create a new service (e.g. called IModalDialogResolver) that would create and return new instances of concrete implementations of IModalDialog. Have all the services injected by hand.
Then I thought about an IOC container (Unity). I have no experience with it. I thought that maybe I don't have to write the IModalDialogResolver as I could register the different implementations of IModalDialog with Unity container => but then how do I use the container inside MainWindowViewModel? I cannot pass the reference to the constructor as that would be a step back to ServiceLocation.
So then I thought that maybe I can use one unity container in the bootstrapper to resolve all the services and use another one internally inside the IModalDialogResolver. But I don't know whether this is a good idea regarding the recommended usage of Unity. I really know too little to judge this. But something tells me that this is not a good idea as it creates a hidden dependency on the container + if the container is a singleton that would be equivalent to just passing the reference into the constructor.
To maybe better explain the mental block that I have: I would like to use an IOC container (e.g. Unity) to have the interfaces constructed and injected by it. But then I cannot just put IModalDialog as a parameter inside a constructor. So probably I really need to wrap this inside a service and implement myself - but then (provided that Unity can do this out of the box) it doesn't make sense to have Unity there in the first place if i cannot use it.
I know one of the alternatives is to put this one service into a base class, but for the sake of argument, let's not consider this. I really would like to learn about the right way to have this solved using dependency injection.
It's perfectly valid and expected for you to access the IoC container within your composition root.
In fact this should be the only location where you container is accessed.
In the example you've given, that's all that is happening - the concrete implementations are being registered in the container within the composition root.
So to answer your question, you don't need to replace the use of the service locator pattern here, as it's just a mechanism for registering the types in the composition root, which is perfectly valid.
If you wish to instantiate the modal dialog service based on some run time conditions, then you should inject a model dialog service factory instead (again an abstraction with an implementation registered in your container), and then the factory would have a method to create the model dialog service and this factory method would take the run time parameters required.
Your factory could then new up the appropriate model dialog service appropriately based on the run time parameters. Alternatively, it could also resolve the appropriate model dialog service from the container, which would obviously require the factory to have a reference to the container.
Most containers support automated factory types, so that you only need to define the interface for the factory, and the container will automatically implement the factory using conventions. Castle.Windsor for example has the Typed Factory Facility and Unity has some equivalents.
I am implementing the builder design pattern to construct different kinds of graph objects to be displayed on a WPF UI. I am using Ninject as my IOC container. However, I am trying to find an elegant extendable solution.
I have a ChartDirector object that takes a IChartBuilder as a dependency. I also have TemperatureChartBuilder and ThresholdChartBuilder that implement IChartBuilder. I want to inject either TemperatureChartBuilder OR ThresholdChartBuilder to ChartDirector depending on an event that is fired or depending on a client call. I have illustrated my problem below in code.
// ChartDirector also depends on this
kernel.Bind<IExample>().To<Example>();
// when called in Method X...
kernel.Bind<IChartBuilder>().To<TemperatureChartBuilder>();
// when called in Method Y...
kernel.Bind<IChartBuilder>().To<ThresholdChartBuilder();
// TemperatureChartBuilder is a dependency of ChartDirector, need a way to dynamically
// allocate which binding to use.
var director = kernel.Get<ChartDirector>();
// without Ninject I would do
var director = new ChartDirector(new TemperatureChartBuilder);
// or
var director = new ChartDirector(new ThresholdChartBuilder);
EDIT:
Coupled with Gary's answer, and noting a slight edit that ChartDirector has another dependency, I now want to do something like this:
var director = kernel.Get<ChartDirector>().WithConstructorArgument(kernel.Get<IChartBuilder>("TemperatureChart"));
Is something like this possible?
If you're just planning to use service location, as in your examples, then named bindings work fine, as per Garys answer.
A better approach, however, is to use constructor injection, and use attributes. For exampl, from the ninject wiki:
Bind<IWeapon>().To<Shuriken>().Named("Strong");
Bind<IWeapon>().To<Dagger>().Named("Weak");
...
class WeakAttack {
readonly IWeapon _weapon;
public([Named("Weak")] IWeapon weakWeapon)
_weapon = weakWeapon;
}
public void Attack(string victim){
Console.WriteLine(_weapon.Hit(victim));
}
}
Based on your comment to Gary, you're (strangely enough) stumbling into territory similar to what I asked a question about a few hours ago. See Remo's answer here: Using WithConstructorArgument and creating bound type
You would use When condition to define when to create the correct instance.
I would suggest using Contextual bindings (named bindings specifically) to accomplish this. That way you can do something like:
// called on app init
kernel.Bind<IChartBuilder>().To<TemperatureChartBuilder>().Named("TempChartBuilder");
kernel.Bind<IChartBuilder>().To<ThresholdChartBuilder().Named("ThreshChartBuilder");
// method X/Y could both call method Z that grabs the correct chart director
var director = new ChartDirector(kernel.Get<IChartBuilder>("TempChartBuilder"));
Where "TempChartBuilder" could be a variable that tells ninject which binding to resolve. So rather binding on the fly you would resolve on the fly but all binding could be defined up front. Typically IOC containers are stored at the application domain level and only need to be defined once. There may be specific cases where you need to bind dynamically but those should be rare.
More info on contextual bindings: https://github.com/ninject/ninject/wiki/Contextual-Binding
Is it possible to expose the DataContext when extending a class in the DataContext? Consider this:
public partial class SomeClass {
public object SomeExtraProperty {
this.DataContext.ExecuteQuery<T>("{SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE}");
}
}
How can I go about doing this? I have a sloppy version working now, where I pass the DataContext to the view model and from there I pass it to the method I have setup in the partial class. I'd like to avoid the whole DataContext passing around and just have a property that I can reference.
UPDATE FOR #Aaronaught
So, how would I go about writing the code? I know that's a vague question, but from what I've seen online so far, all the tutorials feel like they assume I know where to place the code and how use it, etc.
Say I have a very simple application structured as (in folders):
Controllers
Models
Views
Where do the repository files go? In the Models folder or can I create a "Repositories" folder just for them?
Past that how is the repository aware of the DataContext? Do I have to create a new instance of it in each method of the repository (if so that seems in-efficient... and wouldn't that cause problems with pulling an object out of one instance and using it in a controller that's using a different instance...)?
For example I currently have this setup:
public class BaseController : Controller {
protected DataContext dc = new DataContext();
}
public class XController : BaseController {
// stuff
}
This way I have a "global" DataContext available to all controllers who inherit from BaseController. It is my understanding that that is efficient (I could be wrong...).
In my Models folder I have a "Collections" folder, which really serve as the ViewModels:
public class BaseCollection {
// Common properties for the Master page
}
public class XCollection : BaseCollection {
// X View specific properties
}
So, taking all of this where and how would the repository plug-in? Would it be something like this (using the real objects of my app):
public interface IJobRepository {
public Job GetById(int JobId);
}
public class JobRepository : IJobRepository {
public Job GetById(int JobId) {
using (DataContext dc = new DataContext()) {
return dc.Jobs.Single(j => (j.JobId == JobId));
};
}
}
Also, what's the point of the interface? Is it so other services can hook up to my app? What if I don't plan on having any such capabilities?
Moving on, would it be better to have an abstraction object that collects all the information for the real object? For example an IJob object which would have all of the properties of the Job + the additional properties I may want to add such as the Name? So would the repository change to:
public interface IJobRepository {
public IJob GetById(int JobId);
}
public class JobRepository : IJobRepository {
public IJob GetById(int JobId) {
using (DataContext dc = new DataContext()) {
return dc.Jobs.Single(j => new IJob {
Name = dc.SP(JobId) // of course, the project here is wrong,
// but you get the point...
});
};
}
}
My head is so confused now. I would love to see a tutorial from start to finish, i.e., "File -> New -> Do this -> Do that".
Anyway, #Aaronaught, sorry for slamming such a huge question at you, but you obviously have substantially more knowledge at this than I do, so I want to pick your brain as much as I can.
Honestly, this isn't the kind of scenario that Linq to SQL is designed for. Linq to SQL is essentially a thin veneer over the database; your entity model is supposed to closely mirror your data model, and oftentimes your Linq to SQL "entity model" simply isn't appropriate to use as your domain model (which is the "model" in MVC).
Your controller should be making use of a repository or service of some kind. It should be that object's responsibility to load the specific entities along with any additional data that's necessary for the view model. If you don't have a repository/service, you can embed this logic directly into the controller, but if you do this a lot then you're going to end up with a brittle design that's difficult to maintain - better to start with a good design from the get-go.
Do not try to design your entity classes to reference the DataContext. That's exactly the kind of situation that ORMs such as Linq to SQL attempt to avoid. If your entities are actually aware of the DataContext then they're violating the encapsulation provided by Linq to SQL and leaking the implementation to public callers.
You need to have one class responsible for assembling the view models, and that class should either be aware of the DataContext itself, or various other classes that reference the DataContext. Normally the class in question is, as stated above, a domain repository of some kind that abstracts away all the database access.
P.S. Some people will insist that a repository should exclusively deal with domain objects and not presentation (view) objects, and refer to the latter as services or builders; call it what you like, the principle is essentially the same, a class that wraps your data-access classes and is responsible for loading one specific type of object (view model).
Let's say you're building an auto trading site and need to display information about the domain model (the actual car/listing) as well as some related-but-not-linked information that has to be obtained separately (let's say the price range for that particular model). So you'd have a view model like this:
public class CarViewModel
{
public Car Car { get; set; }
public decimal LowestModelPrice { get; set; }
public decimal HighestModelPrice { get; set; }
}
Your view model builder could be as simple as this:
public class CarViewModelService
{
private readonly CarRepository carRepository;
private readonly PriceService priceService;
public CarViewModelService(CarRepository cr, PriceService ps) { ... }
public CarViewModel GetCarData(int carID)
{
var car = carRepository.GetCar(carID);
decimal lowestPrice = priceService.GetLowestPrice(car.ModelNumber);
decimal highestPrice = priceService.GetHighestPrice(car.ModelNumber);
return new CarViewModel { Car = car, LowestPrice = lowestPrice,
HighestPrice = highestPrice };
}
}
That's it. CarRepository is a repository that wraps your DataContext and loads/saves Cars, and PriceService essentially wraps a bunch of stored procedures set up in the same DataContext.
It may seem like a lot of effort to create all these classes, but once you get into the swing of it, it's really not that time-consuming, and you'll ultimately find it way easier to maintain.
Update: Answers to New Questions
Where do the repository files go? In the Models folder or can I create a "Repositories" folder just for them?
Repositories are part of your model if they are responsible for persisting model classes. If they deal with view models (AKA they are "services" or "view model builders") then they are part of your presentation logic; technically they are somewhere between the Controller and Model, which is why in my MVC apps I normally have both a Model namespace (containing actual domain classes) and a ViewModel namespace (containing presentation classes).
how is the repository aware of the DataContext?
In most instances you're going to want to pass it in through the constructor. This allows you to share the same DataContext instance across multiple repositories, which becomes important when you need to write back a View Model that comprises multiple domain objects.
Also, if you later decide to start using a Dependency Injection (DI) Framework then it can handle all of the dependency resolution automatically (by binding the DataContext as HTTP-request-scoped). Normally your controllers shouldn't be creating DataContext instances, they should actually be injected (again, through the constructor) with the pre-existing individual repositories, but this can get a little complicated without a DI framework in place, so if you don't have one, it's OK (not great) to have your controllers actually go and create these objects.
In my Models folder I have a "Collections" folder, which really serve as the ViewModels
This is wrong. Your View Model is not your Model. View Models belong to the View, which is separate from your Domain Model (which is what the "M" or "Model" refers to). As mentioned above, I would suggest actually creating a ViewModel namespace to avoid bloating the Views namespace.
So, taking all of this where and how would the repository plug-in?
See a few paragraphs above - the repository should be injected with the DataContext and the controller should be injected with the repository. If you're not using a DI framework, you can get away with having your controller create the DataContext and repositories, but try not to cement the latter design too much, you'll want to clean it up later.
Also, what's the point of the interface?
Primarily it's so that you can change your persistence model if need be. Perhaps you decide that Linq to SQL is too data-oriented and you want to switch to something more flexible like Entity Framework or NHibernate. Perhaps you need to implement support for Oracle, mysql, or some other non-Microsoft database. Or, perhaps you fully intend to continue using Linq to SQL, but want to be able to write unit tests for your controllers; the only way to do that is to inject mock/fake repositories into the controllers, and for that to work, they need to be abstract types.
Moving on, would it be better to have an abstraction object that collects all the information for the real object? For example an IJob object which would have all of the properties of the Job + the additional properties I may want to add such as the Name?
This is more or less what I recommended in the first place, although you've done it with a projection which is going to be harder to debug. Better to just call the SP on a separate line of code and combine the results afterward.
Also, you can't use an interface type for your Domain or View Model. Not only is it the wrong metaphor (models represent the immutable laws of your application, they are not supposed to change unless the real-world requirements change), but it's actually not possible; interfaces can't be databound because there's nothing to instantiate when posting.
So yeah, you've sort of got the right idea here, except (a) instead of an IJob it should be your JobViewModel, (b) instead of an IJobRepository it should be a JobViewModelService, and (c) instead of directly instantiating the DataContext it should accept one through the constructor.
Keep in mind that the purpose of all of this is to keep a clean, maintainable design. If you have a 24-hour deadline to meet then you can still get it to work by just shoving all of this logic directly into the controller. Just don't leave it that way for long, otherwise your controllers will (d)evolve into God-Object abominations.
Replace {SOME_REALLY_COMPLEX_QUERY_THAT_HAS_TO_BE_IN_RAW_SQL_BECAUSE_LINQ_GENERATES_CRAP_IN_THIS INSTANCE} with a stored procedure then have Linq to SQL import that function.
You can then call the function directly from the data context, get the results and pass it to the view model.
I would avoid making a property that calls the data context. You should just get the value from a service or repository layer whenever you need it instead of embedding it into one of the objects created by Linq to SQL.