I'm experimenting with MVVM for the first time and really like the separation of responsibilities. Of course any design pattern only solves many problems - not all. So I'm trying to figure out where to store application state and where to store application wide commands.
Lets say my application connects to a specific URL. I have a ConnectionWindow and a ConnectionViewModel that support gathering this information from the user and invoking commands to connect to the address. The next time the application starts, I want to reconnect to this same address without prompting the user.
My solution so far is to create an ApplicationViewModel that provides a command to connect to a specific address and to save that address to some persistent storage (where it's actually saved is irrelevant for this question). Below is an abbreviated class model.
The application view model:
public class ApplicationViewModel : INotifyPropertyChanged
{
public Uri Address{ get; set; }
public void ConnectTo( Uri address )
{
// Connect to the address
// Save the addres in persistent storage for later re-use
Address = address;
}
...
}
The connection view model:
public class ConnectionViewModel : INotifyPropertyChanged
{
private ApplicationViewModel _appModel;
public ConnectionViewModel( ApplicationViewModel model )
{
_appModel = model;
}
public ICommand ConnectCmd
{
get
{
if( _connectCmd == null )
{
_connectCmd = new LambdaCommand(
p => _appModel.ConnectTo( Address ),
p => Address != null
);
}
return _connectCmd;
}
}
public Uri Address{ get; set; }
...
}
So the question is this: Is an ApplicationViewModel the right way to handle this? How else might you store application state?
EDIT: I'd like to know also how this affects testability. One of the primary reasons for using MVVM is the ability to test the models without a host application. Specifically I'm interested in insight on how centralized app settings affect testability and the ability to mock out the dependent models.
I generally get a bad feeling about code that has one view model directly communicating with another. I like the idea that the VVM part of the pattern should be basically pluggable and nothing inside that area of the code should depend of the existence of anything else within that section. The reasoning behind this is that without centralising the logic it can become difficult to define responsibility.
On the other hand, based on your actual code, it may just be that the ApplicationViewModel is badly named, it doesn't make a model accessible to a view, so this may simply be a poor choice of name.
Either way, the solution comes down to a break down of responsibility. The way I see it you have three things to achieve:
Allow the user to request to connect to an address
Use that address to connect to a server
Persist that address.
I'd suggest that you need three classes instead of your two.
public class ServiceProvider
{
public void Connect(Uri address)
{
//connect to the server
}
}
public class SettingsProvider
{
public void SaveAddress(Uri address)
{
//Persist address
}
public Uri LoadAddress()
{
//Get address from storage
}
}
public class ConnectionViewModel
{
private ServiceProvider serviceProvider;
public ConnectionViewModel(ServiceProvider provider)
{
this.serviceProvider = serviceProvider;
}
public void ExecuteConnectCommand()
{
serviceProvider.Connect(Address);
}
}
The next thing to decide is how the address gets to the SettingsProvider. You could pass it in from the ConnectionViewModel as you do currently, but I'm not keen on that because it increases the coupling of the view model and it isn't the responsibility of the ViewModel to know that it needs persisting. Another option is to make the call from the ServiceProvider, but it doesn't really feel to me like it should be the ServiceProvider's responsibility either. In fact it doesn't feel like anyone's responsibility other than the SettingsProvider. Which leads me to believe that the setting provider should listen out for changes to the connected address and persist them without intervention. In other words an event:
public class ServiceProvider
{
public event EventHandler<ConnectedEventArgs> Connected;
public void Connect(Uri address)
{
//connect to the server
if (Connected != null)
{
Connected(this, new ConnectedEventArgs(address));
}
}
}
public class SettingsProvider
{
public SettingsProvider(ServiceProvider serviceProvider)
{
serviceProvider.Connected += serviceProvider_Connected;
}
protected virtual void serviceProvider_Connected(object sender, ConnectedEventArgs e)
{
SaveAddress(e.Address);
}
public void SaveAddress(Uri address)
{
//Persist address
}
public Uri LoadAddress()
{
//Get address from storage
}
}
This introduces tight coupling between the ServiceProvider and the SettingsProvider, which you want to avoid if possible and I'd use an EventAggregator here, which I've discussed in an answer to this question
To address the issues of testability, you now have a very defined expectancy for what each method will do. The ConnectionViewModel will call connect, The ServiceProvider will connect and the SettingsProvider will persist. To test the ConnectionViewModel you probably want to convert the coupling to the ServiceProvider from a class to an interface:
public class ServiceProvider : IServiceProvider
{
...
}
public class ConnectionViewModel
{
private IServiceProvider serviceProvider;
public ConnectionViewModel(IServiceProvider provider)
{
this.serviceProvider = serviceProvider;
}
...
}
Then you can use a mocking framework to introduce a mocked IServiceProvider that you can check to ensure that the connect method was called with the expected parameters.
Testing the other two classes is more challenging since they will rely on having a real server and real persistent storage device. You can add more layers of indirection to delay this (for example a PersistenceProvider that the SettingsProvider uses) but eventually you leave the world of unit testing and enter integration testing. Generally when I code with the patterns above the models and view models can get good unit test coverage, but the providers require more complicated testing methodologies.
Of course, once you are using a EventAggregator to break coupling and IOC to facilitate testing it is probably worth looking into one of the dependency injection frameworks such as Microsoft's Prism, but even if you are too late along in development to re-architect a lot of the rules and patterns can be applied to existing code in a simpler way.
If you weren't using M-V-VM, the solution is simple: you put this data and functionality in your Application derived type. Application.Current then gives you access to it. The problem here, as you're aware, is that Application.Current causes problems when unit testing the ViewModel. That's what needs to be fixed. The first step is to decouple ourselves from a concrete Application instance. Do this by defining an interface and implementing it on your concrete Application type.
public interface IApplication
{
Uri Address{ get; set; }
void ConnectTo(Uri address);
}
public class App : Application, IApplication
{
// code removed for brevity
}
Now the next step is to eliminate the call to Application.Current within the ViewModel by using Inversion of Control or Service Locator.
public class ConnectionViewModel : INotifyPropertyChanged
{
public ConnectionViewModel(IApplication application)
{
//...
}
//...
}
All of the "global" functionality is now provided through a mockable service interface, IApplication. You're still left with how to construct the ViewModel with the correct service instance, but it sounds like you're already handling that? If you're looking for a solution there, Onyx (disclaimer, I'm the author) can provide a solution there. Your Application would subscribe to the View.Created event and add itself as a service and the framework would deal with the rest.
Yes, you are on the right track. When you have two controls in your system that need to communicate data, you want to do it in a way that is as decoupled as possible. There are several ways to do this.
In Prism 2, they have an area that is kind of like a "data bus". One control might produce data with a key that is added to the bus, and any control that wants that data can register a callback when that data changes.
Personally, I have implemented something I call "ApplicationState". It has the same purpose. It implements INotifyPropertyChanged, and anyone in the system can write to the specific properties or subscribe for change events. It is less generic than the Prism solution, but it works. This is pretty much what you created.
But now, you have the problem of how to pass around the application state. The old school way to do this is to make it a Singleton. I am not a big fan of this. Instead, I have an interface defined as:
public interface IApplicationStateConsumer
{
public void ConsumeApplicationState(ApplicationState appState);
}
Any visual component in the tree may implement this interface, and simply pass the Application state to the ViewModel.
Then, in the root window, when the Loaded event is fired, I traverse the visual tree and look for controls that want the app state (IApplicationStateConsumer). I hand them the appState, and my system is initialized. It is a poor-man's dependency injection.
On the other hand, Prism solves all of these problems. I kind of wish I could go back and re-architect using Prism... but it is a bit too late for me to be cost-effective.
Related
I'm learning dependency injection, because I don't want my BE to look spaghety no more. I have a good understanding of Asp.Net Core and EF Core. I just never learned dependecy injection properly. I'm playing around with an idea. Let's say, that I create an EmailSenderService (and IEmailSenderService with it). I do the same for CustomLogger and WeatherRepository. Here are the implementations:
Program.cs:
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddScoped<ICustomLogger, CustomLogger>();
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.AddScoped<IWeatherRepository, WeatherRepository>();
// Add swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
CustomLogger.cs
public interface ICustomLogger
{
public void Log(string logText);
}
public class CustomLogger : ICustomLogger
{
public void Log(string logText) => System.Diagnostics.Debug.WriteLine(logText);
}
EmailSenderService.cs
public interface IEmailSenderService
{
public void SendMail(string email, string text);
}
public class EmailSenderService : IEmailSenderService
{
public void SendMail(string email, string text) => System.Diagnostics.Debug.WriteLine($"TO: {email}, TEXT: {text}");
}
WeatherForecastModel.cs
public struct WeatherForecastModel
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
WeatherRepository.cs
public interface IWeatherRepository
{
public WeatherForecastModel[] GetRandomSample();
}
public class WeatherRepository : IWeatherRepository
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public WeatherForecastModel[] GetRandomSample() =>
Enumerable.Range(1, 5).Select(index => new WeatherForecastModel
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
WeatherForecastController.cs
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ICustomLogger _customLogger;
private readonly IEmailSenderService _emailSenderService;
private readonly IWeatherRepository _weatherRepository;
public WeatherForecastController(ICustomLogger customLogger, IEmailSenderService emailSenderService, IWeatherRepository weatherRepository)
{
_customLogger = customLogger;
_emailSenderService = emailSenderService;
_weatherRepository = weatherRepository;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecastModel> Get()
{
_customLogger.Log("Started function GetWeatherForecast");
WeatherForecastModel[] results = _weatherRepository.GetRandomSample();
_customLogger.Log("Started sending mail.");
_emailSenderService.SendMail("some.mail#domain.com", $"Summary of the first result: {results[0].Summary}");
_customLogger.Log("Ended sending mail.");
_customLogger.Log("Ended function GetWeatherForecast");
return results;
}
}
Now, with the whole implementation, in place, I don't like it. Like visually. I do not want to see logging and email sending logic inside of my controller. This is the fundamentaly issue, I'm trying to solve with this question. I could (I implemented it for testing) inject logger inside the EmailSenderService and inside the WeatherRepository and log there, howerver, I do not like that either. I do not want to see logging inside of my logic. So, I thought about something I called LogAwareEmailSenderService. Here is impelementation:
public class LogAwareEmailSenderService : IEmailSenderService
{
private readonly ICustomLogger _customLogger;
private readonly IEmailSenderService _emailSenderService;
public LogAwareEmailSenderService(ICustomLogger customLogger, IEmailSenderService emailSenderService)
{
_customLogger = customLogger;
_emailSenderService = emailSenderService;
}
public void SendMail(string email, string text)
{
_customLogger.Log($"Started sending email to: {email}, containing text: {text}");
_emailSenderService.SendMail(email, text);
_customLogger.Log($"Done sending email to: {email}, containing text: {text}");
}
}
Basically, what I'm trying to achieve, is: Take my original EmailSenderService, then inject it into my LogAwareEmailSenderService. The idea is, that now, I should be able to inject this LogAwareEmailSenderService into my controller without the need to change my controller at all (just remove my previous logging logic), right? And If I achieve this, I can go on and continue, to make something like LogAndEmailAwareWeatherRepository, that will inject LogAwareEmailSenderService and instead of sending mail and logging function start inside of the controller. I will just call LogAndEmailAwareWeatherRepository, that will log these things, and send the email, resulting in controller only calling the important, _weatherRepository.GetRandomSample() -- This call will do the logging and sending mail, using the previously described abstractions.
However, in the first place, I am unable to inject the EmailSenderService inside the LogAwareEmailSenderService. I want them both to be scoped. I trid this approach (in my Program.cs):
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.AddScoped<IEmailSenderService, LogAwareEmailSenderService>();
however I got circular dependency error:
'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService Lifetime: Scoped ImplementationType: DependencyInjectionExample.Services.EmailSenderService.LogAwareEmailSenderService': A circular dependency was detected for the service of type 'DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService'.
DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService(DependencyInjectionExample.Services.EmailSenderService.LogAwareEmailSenderService) -> DependencyInjectionExample.Services.EmailSenderService.IEmailSenderService)'
So, I got some questions:
Am I going about this right? Like, is what I described above, the normal approach to things?
Where should I put my Logging logic? When doing this, I also thought about caching things, meaning, that I would have something like CacheAwareWeatherRepository, that would only care about the caching implementation and then call the WeatherRepository to get data and return them, while caching them.
How to implement my solution?
I still don't understand some parts of dependecy injection, are there any articles/books that helped you personally understand it?
If you've got here, thank you, I know it is long, however I wanted to describe my problem, possible solutions, and questions clearly.
If you have any questions, about anything, please feel free to ask me in comments, or email me (if it's long question) to dibla.tomas#email.cz. I would really like to get to the bottom of this.
PS: This is not about implementation of bussiness logic, or anything like this, this is only for getting data, logging it, caching it and doing abstractions above data access. I implemented this, with idea that you would have one interface and then layers of abstractions. One for getting the actual data (fAb), One for logging the fact (sAb) implementing fAb, One for caching data (tAb) implementing sAb, One for logging the fact of caching (qAb) implementing tAb. And so on.
Am I going about this right? Like, is what I described above, the normal approach to things?
There's not a right/wrong, but what you're describing is an accepted pattern, called the decorator pattern. One service adds behaviors around another one while implementing the same interface.
Where should I put my Logging logic?
Depends on what you mean by "logging logic." The true logic of your logging (opening files and writing to them, e.g.) is already abstracted away behind the logger interface, as it should be.
If you like to have generic messages logged every time a public method is entered or exited, then you can do that with an aspect-oriented Fody Weaver to avoid repetitive code.
The lines of code that decide what to output as a log message, on the other hand, are mostly going to be specific to your implementation. The most useful diagnostic messages are probably going to be ones that need to know contextual information about your specific implementation, and that code needs to be embedded within the implementation code itself. The fact that you "visually don't want to see" calls to the logging service in your controller code is something you should get over. Diagnostic logging is a cross-cutting concern: a responsibility inherent to every class regardless of what their "single responsibility" is supposed to be.
How to implement my solution?
The DI registration method can take a delegate that lets you be more specific about how the type is resolved.
builder.Services.AddScoped<EmailSenderService>(); // allow the next line to work
builder.Services.AddScoped<IEmailSenderService>(p => new LogAwareEmailSenderService(
p.GetRequiredService<ICustomLoggerService>(),
p.GetRequiredService<EmailSenderService>()));
I still don't understand some parts of dependecy injection, are there any articles/books that helped you personally understand it?
Technically not the sort of question we're supposed to be asking on StackOverflow, but I learned from Mark Seeman's Dependency Injection in .NET (affiliate link). It's kind of old now, so library-specific details are outdated, but the principles are enduring.
I thought it might be worth mentioning the Scrutor library which lets you easily specify the decoration setup. For example, you could have:
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.Decorate<IEmailSenderService, LogAwareEmailSenderService>();
Edit: the Decorator pattern is a great way to honour Single Responsibility while enabling the Open/Closed principle: you're able to add new decorators to extend the capabilities of your codebase without updating the existing classes.
However, it comes with the cost of a somewhat more involved setup. The Scrutor library takes care of the decoration so that you don't need to manually code how the services are composed. If you don't have many decorators, or you don't have many levels of decoration, then that advantage might not be useful to you.
The scanning capability is not related to the decorator setup: it's simply another capability that allows one to add classes to the service collection without manually the classes (sort of auto-discovery). You can do this via reflection.
Here's an example of the decorator setup if you also had caching:
builder.Services.AddScoped<IWeatherRepository, WeatherRepository>();
builder.Services.Decorate<IWeatherRepository, DiagnosticsWeatherRepositoryDecorator>();
builder.Services.Decorate<IWeatherRepository, CachedWeatherRepositoryDecorator>();
You could do this manually:
builder.Services.AddScoped<WeatherRepository>();
builder.Services.AddScoped(provider => new DiagnosticsWeatherRepositoryDecorator(provider.GetRequiredService<WeatherRepository>()));
builder.Services.AddScoped<IWeatherRepository>(provider => new CachedWeatherRepositoryDecorator(provider.GetRequiredService<DiagnosticsWeatherRepositoryDecorator>)));
It becomes a bit more involved if the constructors take other parameters. It's completely possible, but really verbose.
I thought I'd also share some advice regarding your 5th question; my experience of dependency injection frameworks is that:
The frameworks are simply a key-value map; if a class needs interface A, then create class B.
Sometimes it's just a key; that happens when you only need to let the framework know that class C exists.
Whenever a class needs to be created, the map of all classes and all interface/class to class mappings are consulted, and whatever the map lists is created.
It seems like you're aware, but these frameworks also manage the lifetime of the objects it creates. For example, a scoped lifetime is linked to the duration of the http request. This means that an IDisposible object created by the framework, will be deposed once the request ends.
In your case:
builder.Services.AddScoped<IEmailSenderService, EmailSenderService>();
builder.Services.AddScoped<IEmailSenderService, LogAwareEmailSenderService>();
The second statement actually overwrites the mapping of the first statement: you can only have one key (in this case IEmailSenderService) in the collection. So when the framework tried to create LogAwareEmailSenderService it saw that LogAwareEmailSenderService needs an IEmailSenderService but the only one it knows about is LogAwareEmailSenderService.
This is why we only list the interface once when we manually tied up the decorated classes. When the Scrutor library is used, it re-maps the types allowing you to list the interface multiple times.
I want to implement MVPO pattern in my windows forms application. As you know there is 1:1 means there is one presenter for one view.
So basicly we can have:
public class MainPresenter
{
IMainView _mainView;
public MainPresenter(IMainView mainView)
{
_myView = myView;
}
}
My question is can one presenter use other presenter so for instance:
public class MainPresenter
{
IMainView _mainView;
ISomeOtherPresenter _otherPresenter;
public MainPresenter(IMainView mainView, IOtherPresenter otherPresenter)
{
_mainView = myView;
_otherPresenter = otherPresenter;
}
}
As a reference i went through video tutorial by Robert Marquez. At his 10 video serie at 10th one he used one rpesenter inside other one
Reference link
at 35:39 you will see his MainPresenter has dependency to IHelpAboutPresenter.
To me it's logical because if HelpAboutView (form) can be opened by button from MainView it's logical MainPresenter has to have access to HelpAboutPresenter which was presented on the video. If not that way how to do so because all the people saying 1:1 and here we have 1 presenter uses other presenter.
It is a bit of a code small to has a cross dependency like that. If you need functionality from another presenter, it is likely the presenters have something in common. So perhaps they should derive from the same base class. Then they can easily share logic without complicating your dependency graph.
public class BasePresenter
{
protected void SharedMethod()
{
//Code that you need to call from both presenters
}
}
public class MainPresenter : BasePresenter
{
IMyView _myView;
public MainPresenter(IMyView myView)
{
_myView = myView;
}
private Foo()
{
SharedFunction();
}
}
public class OtherPresenter : BasePresenter
{
public OtherPresenter(IMyView myView) : base()
{
_myView = myView;
}
private Bar()
{
SharedMethod();
}
}
I would assert that there isn't anything inherently wrong with the approach although one could probably go about it another way.
The "main" view could be acting more along the lines of a front controller. The pattern is more often associated with web-applications although it may still be applicable to desktop applications. For instance, the main MDI view may be the front controller.
Typically a front controller would have some dispatching mechanism to have individual requests (such as menu clicks in a desktop application, or url-based resources in a web-based application) handled by a specific request handler. There is therefore a slight indirection that decouples the front controller from the specific implementation.
In the case of the linked video the relationship is just a bit more coupled in that the About box request (if I understand correctly) is being handled not by a specific request handler but by the front controller.
What makes this appear odd is the fact that the front controller is implemented using the MVP pattern.
I wanted to use SaveFileDialog in my ViewModel, But since it's not correct that bind to a View from ViewModel, I searched for ways to do that. But I found a few answers that doesn't completely separate View form ViewModel, Like this:
public interface IOService
{
void IMessageBox(string Message);
string ISaveFileDialog(string DefaultPath);
}
public class IDialog : IOService
{
public void IMessageBox(string Message)
{
System.Windows.MessageBox.Show(Message);
}
public string ISaveFileDialog(string DefaultPath)
{
System.Windows.Forms.SaveFileDialog dg = new SaveFileDialog
{
InitialDirectory = DefaultPath,
Filter = "PDF files (*.pdf) | *.pdf"
};
dg.ShowDialog();
if (dg.FileName == null)
dg.FileName = string.Empty;
return dg.FileName;
}
}
They said that, this is a Service and using it will separate View from ViewModel. But we have make an Instance from this in ViewModel:
IDialog iDialog = new IDialog();
So I wanna know, What's the diffrence between this method and calling MessageBox or SaveFileDialog from ViewModel directly?
Note: Also I find something that said I could use a Service like the above, But implement it like this:
public class ExportViewModel : BaseViewModel
{
IOService _IOService;
public ExportViewModel(IOService ioservice)
{
_IOService = ioservice;
.
.
}
}
But I don't know how send IOService as a parameter to ExportViewModel (Because we can't create Instances from an Interface!)
You shouldn't pop up dialogs directly from your VM for automated testability.
If you call MessageBox.Show(), your test will get stuck until a person closes the dialog.
If, instead, you use "IMessageBox", for unit tests, you can inject an implementation that doesn't actually show the dialog, but rather returns a specific value (the result).
It's an abstraction used to separate UI concerns from the view model, and to allow you a means to intercept these calls within unit tests. Intercepting these calls allows you to both prevent showing a dialog during a test (which will block execution of your tests, not good) and verify the view model is acting as expected.
There is nothing special about calling it a "Service" or calling the abstraction "IService". It's just an allusion to a common pattern
I need to do something
I can't do it myself
I'll find a service I can hire to do it
I found a service that can do this for me
This service will do it for me
You could just as well call it "IDontTouchUIStuffInMuhViewModel", but that's not as elegant.
Your second problem is solved trivially at runtime by providing an implementation of the interface to your view model. Your view model shouldn't care how it's implemented (polymorphism), so you can pass in a legit implementation at runtime and a fake one during testing.
You can also accomplish this by using Dependency Injection or Inversion of Control. By using a library such as Unity to instantiate your view models, all dependencies are automatically provided, based on how you configured the container.
Background
I'm building a two-tiered C# .net application:
Tier 1: Winforms client application using the MVP (Model-View-Presenter) design pattern.
Tier 2: WebAPI RESTful service sitting on top of Entity Framework and SQL Server.
Currently, I have questions relating to the overall architecture of the Winforms client application. I'm new to programming (about a year) but I've made good progress with this application. I want to step back and re-evaluate my current approach to check that I'm generally heading in the right direction.
Application Domain
The Winforms application is a fairly simple security personnel tracking application. The main view (Form) is the focus of the application, and has different sections which group content into functional areas (e.g. a section for tracking personnel schedules, a section for tracking who is assigned where, etc.). A menu on the side of the application launches secondary views (e.g. history, statistics, contacts, etc.). The idea is that the app could be used by a security office to organize daily operations and then keep a detailed history of everything in a database for reporting on in the future.
Technical Details
As mentioned, the Winforms client is built using the MVP pattern (passive view), focusing on using dependency injection as much as possible (via SimpleInjector IoC container). Each view (form) is paired up with a single presenter. The views implement interfaces, allowing the presenter to control the view (regardless of the concrete implementation). The view raises events for the presenter to subscribe to. Currently, presenters are not allowed to directly communicate to another presenter.
An application controller is used to coordinate the application. This is the area of my application architecture where I'm the most shakey (hence the post title). The application controller is currently used to:
Open new views (forms) and manage open forms.
Facilitate communication between application components via an event aggregator. One presenter publishes an event and any number of presenter can subscribe to that event.
Host session information (i.e. security context/logon, config data, etc.)
The IoC container is registered into the application controller at application start-up. This allows the application controller, for example, to create a presenter from the container, and then have all subsequent dependencies (view, services, etc.) to be automatically handled by the container.
Question
In order to make the Application Controller accessible to all presenters, I have created the controller as a static class.
public static class ApplicationController
{
private static Session _session;
private static INavigationWorkflow _workflow;
private static EventAggregator _aggregator;
#region Registrations
public static void RegisterSession(Session session) {}
public static void RegisterWorkflow(INavigationWorkflow workflow) {}
public static void RegisterAggregator(EventAggregator aggregator) {}
#endregion
#region Properties
public static Session Session
{
get { return _session; }
}
#endregion
#region Navigation
public static void NavigateToView(Constants.View view) {}
#endregion
#region Events
public static Subscription<TMessageType> Subscribe<TMessageType>(Action<TMessageType> action) {}
public static void Publish<TMessageType>(TMessageType message) {}
public static void Unsubscribe<TMessageType>(Subscription<TMessageType> subscription) {}
#endregion
}
Is this considered an acceptable practice to make a static class like this? I mean, it certainly works. It just feels... off? Are there any other holes that you can see in my architecture based on what I have described?
-
** EDIT **
This edit is made in response to Ric .Net’s answer posted below.
I have read through all of your suggestions. As I am committed to utilizing dependency injection to the fullest extent I can, I’m onboard with all of your suggestions. That was my plan from the beginning, but when I ran into things I didn’t understand how to accomplish via injection, I turned to the global static controller class to solve my problems (A god class it is becoming, indeed. Yikes!). Some of those questions still exist:
Event Aggregator
The defining line here is what should be considered optional, I think. I’ll provide a bit more context about my app before outlining my problem. Using web terminology, my main form generally acts like a layout view, hosting navigation controls and a notification section in the left menu, and partial views being hosted in the center. Coming back to winforms terminology, the partial views are just custom made UserControls that I treat like views, and each of them are paired up with their own presenter. I have 6 of these partial views hosted on my main form, and they serve as the meat and potatoes of the application.
As an example, one partial view lists available security guards and another lists potential patrol areas. In a typical use case, a user would drag an available security guard from the available list to one of the potential patrol areas, effectively becoming assigned to that area. The patrol area view would then update to show the assigned security guard and the guard would be removed from the available list view. Utilizing drag-and-drop events, I can handle this interaction.
My questions come when I need to handle other types of interactivity between the various partial views. For example, double clicking on guard that is assigned to a location (as seen in one partial view) could highlight that guard’s name on another partial view showing all personnel schedules, or bring up employee details/history on another partial view. I could see the graph/matrix of what partial views are interested in events occurring in other partial views as becoming quite complex, and I’m not sure how to handle that via injection. With 6 partial views, I wouldn’t want to inject the other 5 partial views/presenters into each one. I was planning on accomplishing this via the event aggregator. Another example I could think of is needing to update data on a separate view (its own form) based off an event that occurs on one of the partial views on the main form.
Session & Form Opener
I really like your thoughts here. I’m going to take these ideas and run with them, and see where I end up!
Security
What are your thoughts on controlling user access to certain functionality based on what type of account they have? The recommendations I’ve been reading online say that security could be implemented by modifying the views based on their account type. The thought being, if a user can’t interact with a UI element to kick off a certain task, then the presenter will never be asked to perform that task. I’m curious if you inject the WindowsUserContext into each presenter and do additional checks, especially for http service bound requests?
I haven’t done too much development on the service side of things yet, but for http service bound requests, I imagine you need to send security information along with each request so that the service can authenticate the request. My plan was to inject the WindowsUserContext directly into the winforms service agents that end up making the service requests (i.e. the security validation would not be coming from the presenter). In that case, the service agents could potentially do a last minute security check before sending off a request.
A static class is of course handy in some cases but there are a lot of downsides to this approach.
The tend to grow into something like a God class. You already see this happening. So this class violates SRP
A static class cannot have dependencies and therefore it needs to use the Service Locator anti pattern to get it's dependencies. This is not a problem perse if you consider this class to be part of the composition root, but nevertheless, this often heads the wrong way.
In the supplied code I see three responsibilities of this class.
EventAggregator
What you call Session information
A service to open other views
Some feedback on this three parts:
EventAggregator
Although this is a widely used pattern and sometimes it can be very powerful I myself am not fond of this pattern. I see this pattern as something that provides optional runtime data where in most cases this runtime data is not optional at all. In other words, only use this pattern for truly optional data. For everything that is not really optional, use hard dependencies, using constructor injection.
The ones that need the information in that case depend upon IEventListener<TMessage>. The one that publish the event, depend upon IEventPublisher<TMessage>.
public interface IEventListener<TMessage>
{
event Action<TMessage> MessageReceived;
}
public interface IEventPublisher<TMessage>
{
void Publish(TMessage message);
}
public class EventPublisher<TMessage> : IEventPublisher<TMessage>
{
private readonly EventOrchestrator<TMessage> orchestrator;
public EventPublisher(EventOrchestrator<TMessage> orchestrator)
{
this.orchestrator = orchestrator;
}
public void Publish(TMessage message) => this.orchestrator.Publish(message);
}
public class EventListener<TMessage> : IEventListener<TMessage>
{
private readonly EventOrchestrator<TMessage> orchestrator;
public EventListener(EventOrchestrator<TMessage> orchestrator)
{
this.orchestrator = orchestrator;
}
public event Action<TMessage> MessageReceived
{
add { orchestrator.MessageReceived += value; }
remove { orchestrator.MessageReceived -= value; }
}
}
public class EventOrchestrator<TMessage>
{
public void Publish(TMessage message) => this.MessageReceived(message);
public event Action<TMessage> MessageReceived = (e) => { };
}
To be able to guarantee events are stored in one single location, we extract that storage (the event) into its own class, the EventOrchestrator.
The registration is as follows:
container.RegisterSingleton(typeof(IEventListener<>), typeof(EventListener<>));
container.RegisterSingleton(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleton(typeof(EventOrchestrator<>), typeof(EventOrchestrator<>));
Usage is trivial:
public class SomeView
{
private readonly IEventPublisher<GuardChanged> eventPublisher;
public SomeView(IEventPublisher<GuardChanged> eventPublisher)
{
this.eventPublisher = eventPublisher;
}
public void GuardSelectionClick(Guard guard)
{
this.eventPublisher.Publish(new GuardChanged(guard));
}
// other code..
}
public class SomeOtherView
{
public SomeOtherView(IEventListener<GuardChanged> eventListener)
{
eventListener.MessageReceived += this.GuardChanged;
}
private void GuardChanged(GuardChanged changedGuard)
{
this.CurrentGuard = changedGuard.SelectedGuard;
}
// other code..
}
If another view will receive a lot of events you could always wrap all IEventListeners of that View in a specific EventHandlerForViewX class which get all important IEventListener<> injected.
Session
In the question you define several ambient context variables as Session information. Exposing this kind of information through a static class promotes tight coupling to this static class and thus makes it more difficult to unit test parts of your application. IMO all information provided by Session is static (in the sense that it doesn't change throughout the lifetime of the application) data that could just as easily be injected into those parts that actually need this data. So Session should completely be removed from the static class. Some examples how to solve this in a SOLID manner:
Configuration values
The composition root is in charge of reading all information from the configuration source (e.g. your app.config file). This information can there be stored in a POCO class crafted for its usage.
public interface IMailSettings
{
string MailAddress { get; }
string DefaultMailSubject { get; }
}
public interface IFtpInformation
{
int FtpPort { get; }
}
public interface IFlowerServiceInformation
{
string FlowerShopAddress { get; }
}
public class ConfigValues :
IMailSettings, IFtpInformation, IFlowerServiceInformation
{
public string MailAddress { get; set; }
public string DefaultMailSubject { get; set; }
public int FtpPort { get; set; }
public string FlowerShopAddress { get; set; }
}
// Register as
public static void RegisterConfig(this Container container)
{
var config = new ConfigValues
{
MailAddress = ConfigurationManager.AppSettings["MailAddress"],
DefaultMailSubject = ConfigurationManager.AppSettings["DefaultMailSubject"],
FtpPort = Convert.ToInt32(ConfigurationManager.AppSettings["FtpPort"]),
FlowerShopAddress = ConfigurationManager.AppSettings["FlowerShopAddress"],
};
var registration = Lifestyle.Singleton.CreateRegistration<ConfigValues>(() =>
config, container);
container.AddRegistration(typeof(IMailSettings),registration);
container.AddRegistration(typeof(IFtpInformation),registration);
container.AddRegistration(typeof(IFlowerServiceInformation),registration);
}
And where you need some specific information, e.g. information to send an email you can just put IMailSettings in the constructor of the type needing the information.
This will also give you the possibility to test a component using different config values, which would be harder to do if all config information had to come from the static ApplicationController.
For security information, e.g. the logged on User the same pattern can be used. Define an IUserContext abstraction, create a WindowsUserContext implementation and fill this with the logged on user in the composition root. Because the component now depends on IUserContext instead of getting the user at runtime from the static class, the same component could also be used in an MVC application, where you would replace the WindowsUserContext with an HttpUserContext implementation.
Opening other forms
This is actually the hard part. I normally also use some big static class with all kinds of methods to open other forms. I don't expose the IFormOpener from this answer to my other forms, because they only need to know, what to do, not which form does that task for them. So my static class exposes this kinds of methods:
public SomeReturnValue OpenCustomerForEdit(Customer customer)
{
var form = MyStaticClass.FormOpener.GetForm<EditCustomerForm>();
form.SetCustomer(customer);
var result = MyStaticClass.FormOpener.ShowModalForm(form);
return (SomeReturnValue) result;
}
However....
I'm not at all happy with this approach, because over time this class grows and grows. With WPF I use another mechanism, which I think could also be used with WinForms. This approach is based on a message based architecture described in this and this awesome blogposts. Although at first the information looks as it is not at all related, it is the message based concept that let these patterns rock!
All my WPF windows implement an open generic interface, e.g. IEditView. And if some view needs to edit a customer, it just get's this IEditView injected. A decorator is used to actually show the view in pretty much the same way as the forementioned FormOpener does it. In this case I make use of a specific Simple Injector feature, called decorate factory decorator, which you can use to create forms whenever it is needed, just as the FormOpener used the container directly to create forms whenever it needs to.
So I did not really test this, so there could be some pitfalls with WinForms, but this code seems to work on a first and single run..
public class EditViewShowerDecorator<TEntity> : IEditView<TEntity>
{
private readonly Func<IEditView<TEntity>> viewCreator;
public EditViewShowerDecorator(Func<IEditView<TEntity>> viewCreator)
{
this.viewCreator = viewCreator;
}
public void EditEntity(TEntity entity)
{
// get view from container
var view = this.viewCreator.Invoke();
// initview with information
view.EditEntity(entity);
using (var form = (Form)view)
{
// show the view
form.ShowDialog();
}
}
}
The forms and decorator should be registered as:
container.Register(typeof(IEditView<>), new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(IEditView<>), typeof(EditViewShowerDecorator<>),
Lifestyle.Singleton);
Security
The IUserContext must the base for all security.
For the userinterface I normally hide all controls/buttons that a certain userrole doesn't have access to. The best place is to perform this in the Load event.
Because I use the command/handler pattern as described here for my all actions external of my forms/views I use a decorator to check if a user has permission to perform this certain command (or query).
I would advise you to read this post a few times until you really get the hang of it. Once you get familiar with this pattern you won't do anything else!
If you have any questions about these patterns and how to apply a (permission)decorator, add a comment!
I have a situation in a project I am currently working on at work that has left my mind restless the entire weekend. First, I need to explain my scenario, and the possible solutions I have considered.
I am writing a composite WCF service that will be aggregating a large amount of external API's . These API's are arbitrary and their existence is all that is needed for this explanation.
These services can be added and removed throughout the period of development. My WCF service should be able to consume the services using several methods (REST,SOAP,etc). For this example, I am focusing on communicating with the external APIS by manually creating the requests in code.
For example, we might have two API's ServiceX and ServiceY.
ServiceX is consumed by POST ing a web request with the data in the request body specifically.
ServiceY is consumed by POST ing a web request with the data appended to the URL(Yes...I know this should be a GET, but I didn't write the external API, so don't lecture me about it.)
In order to avoid redundant, duplicate code, I have wrapped the web requests using the command pattern, and am using a factory to build the requests.
For ServiceX, the data needs to be encoded and put into the request body, as oppose to ServiceY where the data needs to be iterated over and placed on the Post string.
I have a class structure like the following:
public abstract class PostCommandFactory
{
public ICommand CreateCommand();
}
public class UrlPostCommandFactory:PostCommandFactory
{
public ICommand CreateCommand()
{
//Initialize Command Object Here
}
}
public class BodyPostCommandFactory:PostCommandFactory
{
public ICommand CreateCommand()
{
//Initialize Command Object Here
}
}
public interface ICommand
{
string Invoke();
}
public class UrlPostCommand:ICommand
{
public string Invoke()
{
//Make URL Post Request
}
}
public class BodyPostCommand:ICommand
{
public string Invoke()
{
//Make Request Body Post Request
}
}
This allows me to cleanly separate the way that I am binding data to the request when they need to be send out, and essentially, I can also add additional classes to handle GET requests. I am not sure if this is a good use of these patterns. I am thinking an alternative might be using the Strategy pattern and specifying strategy objects for the different Request methods I might need to use. Such as the following:
public class RequestBodyPostStrategy:IPostStrategy
{
public string Invoke()
{
//Make Request Body POST here
}
}
public class UrlPostStrategy:IPostStrategy
{
public string Invoke()
{
//Make URL POST here
}
}
public interface IPostStrategy
{
string Invoke();
}
public class PostContext
{
pubic List<IPostStrategy> _strategies;
public IPostStrategy _strategy;
public PostContext()
{
_strategies = new List<IPostStrategy>();
}
public void AddStrategy(IPostStrategy strategy)
{
_strategies.Add(strategy);
}
public void SetStrategy(IPostStrategy strategy)
{
_strategy = strategy;
}
public void Execute()
{
_strategy.Invoke();
}
}
I am starting to think the Strategy pattern may be the cleaner solution.
Any thoughts?
I would use both.
Command is best practice for encapsulating requests and hiding implementation details. You should probably use it even if you only have one kind of request, as it promotes cleaner code. Essentially it's good practice to consider "what is the absolute minimum the rest of my code needs to know about how requests are executed and handled", which will lead you to the Command pattern.
Strategy is basically configuring your system at runtime with a general, consitent way to handle some ascpect of the operation, in this case generating the requests. This is also a good practice for testing, as you can substitute a test implementation of your strategy/request factory to fake actual connections etc.
Based on the examples for Command and Strategy that you have given, the Command pattern example looks exactly like a Strategy which I guess lead you to Strategy. I would also go with Strategy but would like to add that there's more to Command pattern than what you have included in the example. You should ask yourself questions like:
Do these Commands need to be stored and should be executed later point in time?
Is there a Invoker that needs to invoke these commands without caring about Command internals?
Would you want to have functionality of grouping different Commands together and executing them?
If this is the case then you should choose Command Pattern.