I'm trying to understand MVVM when using I/O, specifically a serial port.
I've implemented my MVVM Model as follows:
Model
public class SerialPortModel
{
private SerialPort Port;
public SerialPortModel()
{
Port = new SerialPort
{
Handshake = Handshake.None,
BaudRate = 9600,
ReadTimeout = 400,
DiscardNull = false,
ReceivedBytesThreshold = 1,
WriteTimeout = 100
};
}
}
My question is:
Should I implement methods such as getting port names, open and close port, etc in the Model or in the ViewModel?
I've read that the Model should just contain data, and not methods?
Or is it OK for the Model to run methods such as opening the COM port?
I wouldn't use it in either. The model should contain meaningful data which in this case would be the data that you are reading from the serial port. A good approach is to make an object that abstracts what you are affecting on the target device.
Let's say you're working with one of the digital scales that have a serial port. You would want methods to read the current weight and set the current time through methods. This keeps all your serialization and deserialization in one spot so you're not passing around a port, raw bytes, or other things. Here is a sample (details, error handling elided):
// Model
public class WeightReport
{
public float Weight { get; set; }
public string Units {get; set; }
}
// Port service
public class MyScale
{
private SerialPort _port;
public MyScale()
{ /* Setup port */ }
public WeightReport ReadWeightReport()
{
var resp = _port.ReadBytes(/* however many bytes */);
// or make a factory, static parser, whatever
var report = new WeightReport(resp);
return report;
}
}
// ViewModel
public class MyViewModel
{
private MyScale _scale;
public WeightReport LastRead { get; set; }
// Add events, delegates, background thread, methods etc. to update LastRead
}
Of course there many ways to do this and it really comes down to your style and how much you expect to maintain this application.
Related
I have a Blazor page that utilizes multiple components within it - how can I implement a State pattern (ideally per-page) that would be able to handle the current state of a page?
Currently I have all of the state and state-manipulation being done on the page (and via injected Services), but I imagine it would be cleaner to implement a state pattern where each page has some kind of State object which then allows you to manipulate the page and its components in a strict manner.
Ideally the State object would implement INotifyPropertyChanged and be able to dynamically have its State updated, but I also don't hate the idea of having the State object relegate State-manipulation to methods on the object to make sure state isn't just 1-off updated on the Blazor page.
I've already tried to implement some kind of MVVM pattern, but that turned into more questions than answers.
I started to create a State object for the current page being worked on, but I'm not sure if I should basically just be putting most of the logic that was on the Blazor page in the State object, or if I should still have some data, but delegating the heavy lifting to the State.
eg: I have some code that used to be in the "OnAfterRenderAsync" function on the Blazor page, but I'm in the process of moving basically everything in there to a "LoadMatterDetails()" function in the State object that is handling that. Does this make sense, or should I only really have object State in the state object, and writing to & reading from the State object when particular pieces of information are available?
public class MatterDetailsState : IMatterDetailsState
{
private readonly IMatterDetailsService matterDetailsService;
private readonly NavigationManager navigationManager;
public bool EditMode { get; private set; } = false;
public int EditMatterId { get; private set; } = 0;
public Matter Matter { get; set; } = new();
public MatterPaymentOptionDetails PaymentDetails { get; set; } = new();
public List<MatterStatus> MatterStatuses { get; private set; } = new();
public MatterDetailsState(
IAppState appState,
IMatterDetailsService matterDetailsService,
NavigationManager navigationManager)
{
this.matterDetailsService = matterDetailsService;
this.navigationManager = navigationManager;
}
public async Task LoadMatterDetails()
{
// Query Params handling
var uri = navigationManager.ToAbsoluteUri(navigationManager.Uri);
var decryptedUri = HelperFunctions.Decrypt(uri.Query);
var queryParamFound = QueryHelpers.ParseQuery(decryptedUri).TryGetValue("MatterID", out StringValues uriMatterID);
if (queryParamFound)
{
EditMatterId = Convert.ToInt32(uriMatterID);
EditMode = !String.IsNullOrEmpty(uriMatterID) && EditMatterId > 0;
}
await LoadMatterStatuses();
if (EditMode)
{
Matter = await matterDetailsService.GetMatterByIdAsync(EditMatterId);
PaymentDetails = await matterDetailsService.GetMatterPaymentInfoByMatterId(EditMatterId);
}
}
private async Task LoadMatterStatuses()
{
MatterStatuses = await matterDetailsService.GetAvailableMatterStatusesAsync();
}
}
Basically, should I instead of having more or less the entire function in the State object, or only make the calls like setting Matter & PaymentDetails go through functions in the State object? Not sure what the standard for this is.
I've used Fluxor, which is a Flux/Redux library for Blazor, and have liked it. It holds all your state in an object which you can inject into your component for read access. You then manage state by dispatching actions from your components which are processed by effects or reducers which are essentially methods that process the action and make changes to state. It keeps everything neat, separated and very testable in my experience.
https://github.com/mrpmorris/Fluxor
There isn't a "standard", but applying good coding practices such as the "Single Responsivity Principle" and Clean Design principles drives you in a certain direction.
I divide the presentation and UI code into three:
UI - components and UI logic
State - data that you want to track state on.
Data Management - getting, saving,....
Each represented by one or more objects (Data Management is the ViewModel in MVVM).
You can see an example of this in this answer - https://stackoverflow.com/a/75157903/13065781
The problem is then how do you create a ViewModel instance that is scoped the same as the Form component. You either:
Scope the VM as transient - you can cascade it in the form if sub components need direct access to it. This is the approach in the referenced example.
Create an instance from the IServiceProvider using ActivatorUtilities and deal with the disposal in the form component.
If the VM implements IDisposable/IAsycDisposable the you have to do the second.
The following extension class adds two methods to the IServiceProvider that wrap up this functionality.
public static class ServiceUtilities
{
public static bool TryGetComponentService<TService>(this IServiceProvider serviceProvider,[NotNullWhen(true)] out TService? service) where TService : class
{
service = serviceProvider.GetComponentService<TService>();
return service != null;
}
public static TService? GetComponentService<TService>(this IServiceProvider serviceProvider) where TService : class
{
var serviceType = serviceProvider.GetService<TService>()?.GetType();
if (serviceType is null)
return ActivatorUtilities.CreateInstance<TService>(serviceProvider);
return ActivatorUtilities.CreateInstance(serviceProvider, serviceType) as TService;
}
}
Your form then can look something like this:
public partial class UIForm: UIWrapperBase, IAsyncDisposable
{
[Inject] protected IServiceProvider ServiceProvider { get; set; } = default!;
public MyEditorPresenter Presenter { get; set; } = default!;
private IDisposable? _disposable;
public override Task SetParametersAsync(ParameterView parameters)
{
// overries the base as we need to make sure we set up the Presenter Service before any rendering takes place
parameters.SetParameterProperties(this);
if (!initialized)
{
// Gets an instance of the Presenter from the Service Provider
this.Presenter = ServiceProvider.GetComponentService<MyEditorPresenter>() ?? default!;
if (this.Presenter is null)
throw new NullReferenceException($"No Presenter could be created.");
_disposable = this.Presenter as IDisposable;
}
return base.SetParametersAsync(ParameterView.Empty);
}
//....
public async ValueTask DisposeAsync()
{
_disposable?.Dispose();
if (this.Presenter is IAsyncDisposable asyncDisposable)
await asyncDisposable.DisposeAsync();
}
}
This class accumulates values + knows at current moment the difference between current sum and sum 1 minute ago. Its client uses it in such way: adds new value for every incoming data chunk and gets the difference. Now, there's a problem with restoring its state. Suppose application gets recycled, and this data in pump for previous minute is lost and first minute after recycling Change will equal 0, so I'd have to wait for a minute to be able to calculate difference. How to fix it?
public class ChangeEstimator
{
private int sum;
private Subject<int> sumPump;
private IConnectableObservable<int> hotSumPump;
public int Sum
{
get
{
return sum;
}
private set
{
sum = value;
sumPump.OnNext(value);
}
}
public int Change { get; private set; }
public void Start()
{
sumPump = new Subject<int>();
hotSumPump = sumPump.Publish();
var changePeriod = TimeSpan.FromMinutes(1);
hotSumPump.Delay(changePeriod)
.Subscribe(value =>
{
Change = Sum - value;
});
hotSumPump.Connect();
}
public void AddNewValue(int newValue)
{
Sum += newValue;
}
}
UPDATE
In the code below you can see the explanation. The client subscribes to transaction stream, and with every new transaction it updates the estimator. Also client exposes IObservable source of snapshots which pushes snapshot of data to listeners which can be UI or database. The problem is when recycling happens, UI will be shown not real Change but 0. If this problem is too specific for Stackoverflow please forgive me. I was advised to use RabbitMQ to keep persistence of changes. Do you think it could work for this problem?
public class Transaction
{
public int Price { get; set; }
}
public class AlgorithmResult
{
public int Change { get; set; }
}
public interface ITransactionProvider
{
IObservable<Transaction> TransactionStream { get; }
}
public class Client
{
private ChangeEstimator estimator = new ChangeEstimator();
private ITransactionProvider transactionProvider;
public Client(ITransactionProvider transactionProvider)
{
this.transactionProvider = transactionProvider;
}
public void Init()
{
transactionProvider.TransactionStream.Subscribe(t =>
{
estimator.AddNewValue(t.Price);
});
}
public IObservable<AlgorithmResult> CreateSnaphotsTimedSource(int periodSeconds)
{
return Observable
.Interval(TimeSpan.FromSeconds(periodSeconds))
.Select(_ =>
{
AlgorithmResult snapshot;
snapshot = new AlgorithmResult
{
Change = estimator.Change
};
return snapshot;
})
.Where(snapshot => snapshot != null);
}
}
Your application gets restarted and has no memory (pun intended) of its previous life. No Rx tricks (within this application) can help you.
As discussed, you should figure out the business requirements and consider state initialization during startup.
You might want to consider storing latest state via I/O source or separating application logic between message sender and consumer in order to implement a queue.
I have to answer my own question because I got an answer from someone and this works in my case. I agree that the correct answer depends on the business logic and I think I had explained it as clearly as I could.
So, here the right way to deal with possible application recycle is to put the class ChangeEstimator to outer process and exchange messages with it.
I use AMQP to send messages to estimator (RabbitMQ). To key point here is that the risk that external process will close/recycle is really small compared to that of web application in which the rest is contained.
I want to use EF behind my WCF service to fetch data and display it to the client. I need the following suggestions:
Do I need to have the same interface for all the views (e.g. students, teachers etc.) or do I need to have a different interface and service for every table (or view)
Do I need to generate the database calls within my service (.svc) or some other architecture is preferred?
public Student[] GetAllStudents()
{
//database generation code here
}
How can I use EF code-first approach to generate database. I know that for an MVC app, you need to set the initializer in Global.asax or in web.config but I am not sure how it's called in this case. My model looks like this:
[DataContract]
public class Student
{
[DataMember]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[DataMember]
public string Type { get; set; }
[DataMember]
public string Subject { get; set; }
[DataMember]
public string Description { get; set; }
}
What you really should do is break up your system in to more separate layers. Instead of having a WCF call that directly queries the database, create a "buisness logic" layer that translates the information that the WCF call provides you to what the EF call needs to know. This is called a N-Tier application
public class SchoolAPI : ISchoolAPI
{
private DataAccessLayer _dal = new DataAccessLayer();
public Student[] GetAllStudents()
{
return _dal.GetStudents(null, null);
}
public Student[] GetAllScienceStudents()
{
return _dal.GetStudents(null, DataAccessLayer.ScienceStudentType);
}
}
private class DataAccessLayer
{
public static readonly ScienceStudentType = //...
public Student[] GetStudents(string subject, string type)
{
using(var ctx = new SchoolContext())
{
IQueryable<Student> studentQuery = ctx.Students;
if(subject != null)
studentQuery = studentQuery.Where(s=>s.Subject == subject);
if(type != null)
studentQuery = studentQuery.Where(s=>s.Type == type);
return studentQuery.ToArray();
}
}
}
The caller of the WCF call does not need to know what the string ScienceStudentType is, all it cares about is that it gets the science students. By seperating the business logic from the database call the caller of your service no longer needs to know.
For EF it will initialize on the first time the framework goes out to "touch" the database and detects that it is not there if it is set up to do so. This is done in the constructor of SchoolContext but is getting a little too broad for this answer. I recommend finding a tutorial on EF and get it working in a simple test enviorment without WCF (maybe a simple console app that just calls GetStudents() then move in in to a WCF environment.
Hoping someone could clear things up. In the following ViewModel, does using Entity Framework as my model eliminate the need to use [Model] and [[ViewModelToModel(...)] attributes? The code runs the same with or without them, because the binding in the view ignores them and binds to the ObservableCollection.
Comments?
public class MainWindowViewModel : ViewModelBase
{
Models.OneHour_DataEntities ctx;
public MainWindowViewModel()
: base()
{
Save = new Command(OnSaveExecute, OnSaveCanExecute);
ctx = new Models.OneHour_DataEntities();
Customers = new ObservableCollection<Models.Customer>(ctx.Customers);
}
public ObservableCollection<Models.Customer> Customers
{
get { return GetValue<ObservableCollection<Models.Customer>>(CustomersProperty); }
set { SetValue(CustomersProperty, value); }
}
public static readonly PropertyData CustomersProperty = RegisterProperty("Customers", typeof(ObservableCollection<Models.Customer>), null);
public Command Save { get; private set; }
private bool OnSaveCanExecute()
{
return true;
}
private void OnSaveExecute()
{
ctx.SaveChanges();
}
}
Catel uses different interfaces to take advantage of the models. For example, it uses the following interfaces:
IEditableObject => undoing changes to model when user cancels
INotifyPropertyChanged => update view model when model updates
If your entity model implements these interfaces, you can define a property as a model.
In your example however, you use an ObservableCollection (thus a list of models) as a model. That is not supported (or, again, the collection must support IEditableObject and INotifyPropertyChanged).
I would like to know if you find the following pattern meaningful in domain driven design.
The domain layer consists of model and repository. The application layer consists of services that handles queries from the user interface, or from controllers in the Model-View-Controller pattern.
Details of the structure:
// Assembly Model:
public class Phrase
{
public int PhraseId { get; private set; }
public string PhraseText { get; private set; }
public Phrase(string phraseText) { this.PhraseText = phraseText; }
public void SetId(int phraseId) { this.PhraseId = phraseId; }
}
// Assembly Repository (references assembly Model):
public interface IPhraseRepository
{
Phrase SavePhrase(Phrase phrase);
Phrase GetPhrase(int phraseId);
}
// Assembly Services (references assemblies Model and Repository):
public class PhraseService
{
private IPhraseRepository _phraseRepository;
public PhraseService(IPhraseRepository phraseRepository)
{
_phraseRepository = phraseRepository;
}
public Phrase SavePhrase(string phraseText)
{
Phrase phrase = _phraseRepository.SavePhrase(new Phrase(phraseText));
// doing other things like sending mail, logging, etc.
// ...
return Phrase;
}
}
Particularly, would it make sense to move the method into the Phrase entity class? In that case, how would that be called?
EDIT:
The example above has been modified after the answer from moffdub and the comment from Adeel Ansari. The changes are highlighted.
I would like to ask about the added IPhraseRepository.GetPhrase(phraseId) and how you would include that?
The repository should take in a Phrase, not a string. I'm also not sure why the SavePhrase method returns a Phrase. I tend to make such methods void methods.
Also, be wary of making every property in your domain model have public getters and setters. That can lead you to an anemic domain model.
Just some thoughts:
SetId(int phraseId) should not be public
Phrase could implement IPhrase (or IPhraseAggregate) which would not expose SetId(..)
SavePhrase(Phrase phrase) could (should?) return void if the reference to the phrase entity stays "valid" after saving:
public void SavePhrase(string phraseText)
{
Phrase phrase = new Phrase(phraseText); // NOTE: keep a reference to phrase
this._phraseRepository.SavePhrase(phrase); // NOTE: returns void
return phrase; // NOTE: assume the repository sets the phrase.PhraseId
}