I am trying to pass information from ViewModelA to ViewModelB as follows. When I was debugging the code, I could able to observe my SCoordinates has 5 objects in it, but when I try to get these 5 objects in the ViewModelB, it is coming null. The other information (date, sId) is not null, only SCoordinates is null.
ViewModelA
public ObservableCollection<SVModel> SCoordinates
{
get { return _sp; }
set
{
_sp = value;
RaisePropertyChanged(() => SCoordinates );
}
}
private void SSelected(SVModel obj)
{
ShowViewModel<ViewModelB>(new { sId = obj.Id, date = DateTime.Now, sCoordinates = SCoordinates });
}
ViewModelB
public void Init(string sId, DateTime date, ObservableCollection<SVModel> sCoordinates)
{
var sp = _sService.GetService(sId);
SVModel = new SVModel (sp);
// the following gets null
SCoordinates = sCoordinates;
}
As the documentation clearly states:
Note that due to serialization requirements, the only available parameter types used within this technique are only:
it must contain a parameterless constructor
it should contain only public properties with both get and set access
these properties should be only of types:
int, long, double, string, Guid, enumeration values
In other words, only valuetypes are supported to be used as members of the parameters.
I see this as a big design flaw in MvvmCross. I'm not saying this should be supported but the framework should throw an exception if the constraints from the documentation aren't followed. So instead of silently accepting that you pass a class that not meets the constraints and pass null, a clear exception should be thrown by the framework. Thereby informing you instead of letting you search for the answer here.
This philosophy even has a name: Fail fast!
I can think of 3 options here:
1) {Bad practice but easy} Create a Service (singleton by default in mvvmcross) to hold your SCoordinates collection instead of keeping them in the ViewModel. This could be considered bad practice because Services are supposed to be stateless. Though it will work.
UPDATE
As an answer to a comment question, here´s an example. If you work with MvvmCross you should be familiar with this:
public class App : MvxApplication
{
public override void Initialize()
{
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
/// ...
}
}
So you create a simple class ending with "Service" and the corresponding interface in your core project.
public interface ICoordinatesService
{
ObservableCollection<SVModel> Coordinates { get; set; }
}
public class CoordinatesService : ICoordinatesService
{
public ObservableCollection<SVModel> Coordinates { get; set; }
}
To access a service in your viewmodel you can use constructor injection and to gain access to the collection hosted in the service without using methods, the easier way would be something as follows:
public class YourViewModel : MvxViewModel
{
public ObservableCollection<SVModel> Coordinates => _coordinatesService.Coordinates;
private readonly ICoordinatesService _coordinatesService;
public YourViewModel(ICoordinatesService coordinatesService)
{
_coordinatesService = coordinatesService;
}
public void SaveSomeCoordinates()
{
Coordinates.Add(new SVModel());
}
public void RemoveSomeCoordinates()
{
Coordinates.RemoveAt(1);
}
public void ResetCoordinates()
{
_coordinatesService.Coordinates = new ObservableCollection<SVModel>();
}
}
2) Use a local cache system to save SCoordinates. You can do it through a Service:
public class Service
{
public ObservableCollection<SVModel> RestoreCoordinates()
{
// get from cache
}
public bool SaveCoordinates(ObservableCollection<SVModel> coordinates)
{
// save to cache
}
}
Then, on your ViewModel.Init() you can restore your data.
I recommend using Akavache as an easy local cache, but you could use other libraries or a plain SQLite table
3) Serialize your collection with Json.Net and pass it to ShowViewModel() init params as a string. Then deserialize it on the Init() method
Related
Often in my applications built with Caliburn Micro I have a need to store some global data; this could be app specific config, authentication properties, etc. I generally put them in a class called "Session" and inject that via constructor injection so that every view model has a reference to a single instance of Session.
I found a case where I wanted a guard method on two different view models to be linked to a Session variable; the issue is guard methods are generally notified of changes in the setter of the changed variable. Since it's a global, it doesn't know what depends on it. (It occurs to me that this pattern of variables being aware of what guard is hooked into them is bad, but when it's all in the same ViewModel it doesn't matter much.)
I could throw an event, but that's messy and a lot of work for something that should be simple.
I could try to identify every spot where it may have been updated and manually notify, but that's error prone.
public class MyViewModel: Screen{
public MyViewModel(SessionInfo session){
Session = session;
}
public CanTakeAction { get { return !string.isNullOrWhitespace(Session.SomeProperty); } }
}
public class SessionInfo {
public SessionInfo(){}
public string SomeProperty { get; set; }
// this is where I would normally notify a guard method, but this is not going to work
NotifyOfPropertyChange(() => CanTakeAction); // except it doesn't know about CanTakeAction
}
One possible solution would be to introduce a base ViewModel, which has the guard methods (virtual). For Example,
public class ViewModelBase:Screen
{
private SessionInfo _sessionInfo;
public ViewModelBase(SessionInfo sessionInfo)
{
_sessionInfo = sessionInfo;
}
public void NotifyGuardMethods()
{
NotifyOfPropertyChange(nameof(CanTakeAction));
}
public virtual bool CanTakeAction { get; set; } = false;
}
For all the ViewModels that needs to be notified by the change in Session, you could now derieve from the ViewModelBase.
public class ShellViewModel:ViewModelBase
{
public override bool CanTakeAction { get=>//its own logic; set=>//its own logic; };
}
You could now introduce Events to the ViewModelBase, which could use the NotifyGuardMethods defined in the base class to notify all other view models. This ensures the messsy Events part would be restricted to one class alone (base view model).
I have a few business objects that have to be used together to get a specific outcome. Take a look at the following very simplyfied example for reference.
My question is: how do I get a reference to the agent using DI in the Station class ? I mostly prefer constructor injection, but that is not possible the Station class already has a stationCode as a required item.
Any ideas ?
Usage:
var station1 = new Station("xx");
var station2 = new Station("yy");
var route = new Route(station1, station2);
var length = route.GetLength();
public class Location
{
public int Position {get; set;}
}
public interface IAgent
{
Location GetLocation(string stationCode);
}
public class Station
{
private string _stationCode;
public Station(string stationCode)
{
_stationCode = stationCode;
}
public Location GetLocation()
{
// issue here: how to get a reference to the agent instance using DI
_agent.GetLocation(_stationCode);
}
}
public class Route
{
private Station _station1;
private Station _station2;
public Route(Station station1, Station station2)
{
_station1 = station1;
_station2 = station2;
}
public int GetLength()
{
var location1 = _station1.GetLocation();
var location2 = _station2.GetLocation();
result = location2.Position - location1.Position;
return result;
}
}
Your classes seem to be having an identity crisis. When using DI, you should have just 2 types of classes to deal with - injectables and newables. Your Station class seems like a kludge because it both provides a service (has dependencies) and has state. To make your classes DI-friendly, you should design classes that only provide state to classes that only do something with the state (services).
Route
This class is injectable - that is, it should be wired from the DI container.
public interface IRoute
{
int GetLength(Station station1, Station station2);
}
public class Route : IRoute
{
private readonly IAgent _agent;
public Route(IAgent agent)
{
if (agent == null) throw new ArgumentNullException("agent");
_agent = agent;
}
public int GetLength(Station station1, Station station2)
{
var location1 = _agent.GetLocation(station1.StationCode);
var location2 = _agent.GetLocation(station2.StationCode);
result = location2.Position - location1.Position;
return result;
}
}
Station
This class is newable - that is, you should always use the new keyword to instantiate it.
public class Station
{
private string _stationCode;
public Station(string stationCode)
{
_stationCode = stationCode;
}
public string StationCode
{
get { return _stationCode; }
// Optional: provide setter here
}
}
Usage
var station1 = new Station("xx");
var station2 = new Station("yy");
// IRoute is injected where you need to make the calculation
var length = _route.GetLength(station1, station2);
Perhaps it would be better to rename Route to something more appropriate, since it does not provide a route, it calculates the route length.
Frankly, if your Station class doesn't have any other state than a single string variable, it would probably make more sense to eliminate the class and just use strings for station1 and station2. But this is mostly just a matter of personal taste.
The concept of two types of classes to deal with, injectables and newables, is a good idea. But when newables should contain only limited business logic, you are drifting away from pure object-oriented concepts. When you write code for a complex domain model, your newable business classes contain both business logic and data. That´s also the intention of the question, I assume. The Station and Route classes are simple examples that contain much more logic and data in reality.
So I would suggest to have better separation of concerns, by separating code for storage from you business logic. I see two common solutions for this.
When data is loaded in memory, a separate StationStore class is an injectable that loads stations and stores them in the context of the business domain, eg. in a static property:
public IEnumarable<Station> Station.Store { get; internal set; }
All DI code can be hidden in a business base class. It´s less disturbing to put DI dependencies there. So an agent can be resolved in the generic base class based on the template types provided.
public class Station : BusinessClass<Station, StationAgent>
{
public string StationCode { get; internal set; }
public Location Location { get; internal set; }
public Station(string stationCode)
{
base.Load(stationCode, this);
}
}
I am facing a unique problem. We have a download functionality in our application in which we have a drop-down which contains type of file user need to download i.e. pdf,csv or excel
To implement this problem we have create one Interface IFileDownaload and three different class clsCSV,ClsPDF and clsExcel which are implemented by IFileDownaload
Now my problem is how to inititate a class on the basis of Dropdown value because i dont want to write down if-else statement
if(option=="pdf") type
because in future if we introduce a new file download type then it will impact us to re-write whole logic again
Any suggestion
You can define abbreviation for each class you have, so that you'll have something like this:
public interface IFileDownload
{
string Abbreviation { get; }
}
public class PDFDonwload : IFileDownload
{
public string Abbreviation { get; private set; }
}
Then you can make some class, i.e. factory, which have instances of all filedownloaders you have and which iterates through their Abbreviations till it finds proper class. It can be implemented like this:
public static class DownloadHander
{
private static List<IFileDownload> _handlers;
static DownloadHander()
{
_handlers = new List<IFileDownload>();
}
public static void Initialize()
{
_handlers.Add(new PDFDonwload());
}
public static Stream HandleDownload(string abbreviation)
{
foreach (var fileDownload in _handlers)
{
if (fileDownload.Abbreviation == abbreviation)
{
//and here you make a stream for client
}
}
throw new Exception("No Handler");
}
}
When I have a number of classes which implement a certain type and those classes are stateless services rather than entities, I use a Registry rather than a Factory.
Your Registry has instances of all the IFileDownload-implementing classes injected into it in an array:
public class FileDownloaderRegistry
{
private readonly IFileDownload[] _downloaders;
public FileDownloaderRegistry(IFileDownload[] downloaders)
{
_downloaders = downloaders;
}
}
You then have a property on IFileDownload which indicates the file type handled by the downloader:
public interface IFileDownload
{
string FileType { get; }
// etc.
}
And finally a method on your Registry which takes the file type and delegates the work to the appropriate downloader:
public string DownloadFile(string fileName, string fileType)
{
var handlingDownloader = _downloaders
.FirstOrDefault(d => d.FileType == fileType);
if (handlingDownloader == null)
{
// Probably throw an Exception
}
return handlingDownloader.Download(fileName);
}
DI containers will often implicitly understand arrays, so just registering the various IFileDownloads should end up with them in the array injected into the Registry's constructor. e.g. with StructureMap you use:
For<IFileDownload>().Use<ClsCSV>();
For<IFileDownload>().Use<ClsPDF>();
For<IFileDownload>().Use<ClsExcel>();
Adding a new IFileDownload is then a matter of writing the class and adding it to the set of IFileDownloads registered with your DI container. You can also have the container manage the lifetimes of each object so (if they're stateless) they're only instantiated once each, when they're first needed.
Is there some kind of way to let AutoFixture create properties with an internal setter?
I've looked at the AutoFixture source and found that in the AutoPropertiesCommand the GetProperties method checks whether a property has GetSetMethod() != null.
With an internal setter this returns null, unless you set the ignorePublic argument to true.
The easiest thing would of course be to make the setter public but in the project I'm working on this just wouldn't be the right solution.
Below is a simplified piece of code from the project as an example.
public class Dummy
{
public int Id { get; set; }
public string Name { get; internal set; }
}
public class TestClass
{
[Fact]
public void Test()
{
var dummy = new Fixture().Create<Dummy>();
Assert.NotNull(dummy.Name);
}
}
Ideally, the tests shouldn't have to interact with the internal members of a class, since they are explicitly excluded from its public API. Instead, these members would be tested indirectly by the code paths initiated through the public API.
However, if this isn't feasible in your particular situation, a possible workaround could be to explicitly assign a value to the internal properties from within the tests.
You can do that in one of two ways:
By exposing all internal members within the assembly to the test project using the InternalsVisibleTo attribute.
By representing the modifiable state of the class in a specific interface and implement that explicitly.
In your example, option 1 would be:
// [assembly:InternalsVisibleTo("Tests")]
// is applied to the assembly that contains the 'Dummy' type
[Fact]
public void Test()
{
var fixture = new Fixture();
var dummy = fixture.Create<Dummy>();
dummy.Name = fixture.Create<string>();
// ...
}
Option 2, instead, would be something like:
public class Dummy : IModifiableDummy
{
public string Name { get; private set; }
public void IModifiableDummy.SetName(string value)
{
this.Name = value;
}
}
[Fact]
public void Test()
{
var fixture = new Fixture();
var dummy = fixture.Create<Dummy>();
((IModifiableDummy)dummy).SetName(fixture.Create<string>());
// ...
}
Option 1 is fairly quick to implement, but has the side effect of opening up all internal members within the assembly, which may not be what you want.
Option 2, on the other hand, allows you to control what part of the object's state should be exposed as modifiable, while still keeping it separated the object's own public API.
As a side note, I'd like to point out that, since you're using xUnit, you can take advantage of AutoFixture's support for Data Theories to make your tests slightly more terse:
[Theory, AutoData]
public void Test(Dummy dummy, string name)
{
((IModifiableDummy)dummy).SetName(name);
// ...
}
If you prefer to set the Name property to a known value while still keeping the rest of the Dummy object anonymous, you have also the possibility to combine the two within the same Data Theory:
[Theory, InlineAutoData("SomeName")]
public void Test(string name, Dummy dummy)
{
((IModifiableDummy)dummy).SetName(name);
// ...
}
I recently started reading Evans' Domain-Driven design book and started a small sample project to get some experience in DDD. At the same time I wanted to learn more about MongoDB and started to replace my SQL EF4 repositories with MongoDB and the latest official C# driver.
Now this question is about MongoDB mapping. I see that it is pretty easy to map simple objects with public getters and setters - no pain there. But I have difficulties mapping domain entities without public setters. As I learnt, the only really clean approach to construct a valid entity is to pass the required parameters into the constructor. Consider the following example:
public class Transport : IEntity<Transport>
{
private readonly TransportID transportID;
private readonly PersonCapacity personCapacity;
public Transport(TransportID transportID,PersonCapacity personCapacity)
{
Validate.NotNull(personCapacity, "personCapacity is required");
Validate.NotNull(transportID, "transportID is required");
this.transportID = transportID;
this.personCapacity = personCapacity;
}
public virtual PersonCapacity PersonCapacity
{
get { return personCapacity; }
}
public virtual TransportID TransportID
{
get { return transportID; }
}
}
public class TransportID:IValueObject<TransportID>
{
private readonly string number;
#region Constr
public TransportID(string number)
{
Validate.NotNull(number);
this.number = number;
}
#endregion
public string IdString
{
get { return number; }
}
}
public class PersonCapacity:IValueObject<PersonCapacity>
{
private readonly int numberOfSeats;
#region Constr
public PersonCapacity(int numberOfSeats)
{
Validate.NotNull(numberOfSeats);
this.numberOfSeats = numberOfSeats;
}
#endregion
public int NumberOfSeats
{
get { return numberOfSeats; }
}
}
Obviously automapping does not work here. Now I can map those three classes by hand via BsonClassMaps and they will be stored just fine. The problem is, when I want to load them from the DB I have to load them as BsonDocuments, and parse them into my domain object. I tried lots of things but ultimately failed to get a clean solution. Do I really have to produce DTOs with public getters/setters for MongoDB and map those over to my domain objects? Maybe someone can give me some advice on this.
It is possible to serialize/deserialize classes where the properties are read-only. If you are trying to keep your domain objects persistance ignorant, you won't want to use BsonAttributes to guide the serialization, and as you pointed out AutoMapping requires read/write properties, so you would have to register the class maps yourself. For example, the class:
public class C {
private ObjectId id;
private int x;
public C(ObjectId id, int x) {
this.id = id;
this.x = x;
}
public ObjectId Id { get { return id; } }
public int X { get { return x; } }
}
Can be mapped using the following initialization code:
BsonClassMap.RegisterClassMap<C>(cm => {
cm.MapIdField("id");
cm.MapField("x");
});
Note that the private fields cannot be readonly. Note also that deserialization bypasses your constructor and directly initializes the private fields (.NET serialization works this way also).
Here's a full sample program that tests this:
http://www.pastie.org/1822994
I'd go with parsing the BSON documents and move the parsing logic to a factory.
First define a factory base class, which contains a builder class. The builder class will act as the DTO, but with additional validation of the values before constructing the domain object.
public class TransportFactory<TSource>
{
public Transport Create(TSource source)
{
return Create(source, new TransportBuilder());
}
protected abstract Transport Create(TSource source, TransportBuilder builder);
protected class TransportBuilder
{
private TransportId transportId;
private PersonCapacity personCapacity;
internal TransportBuilder()
{
}
public TransportBuilder WithTransportId(TransportId value)
{
this.transportId = value;
return this;
}
public TransportBuilder WithPersonCapacity(PersonCapacity value)
{
this.personCapacity = value;
return this;
}
public Transport Build()
{
// TODO: Validate the builder's fields before constructing.
return new Transport(this.transportId, this.personCapacity);
}
}
}
Now, create a factory subclass in your repository. This factory will construct domain objects from the BSON documents.
public class TransportRepository
{
public Transport GetMostPopularTransport()
{
// Query MongoDB for the BSON document.
BsonDocument transportDocument = mongo.Query(...);
return TransportFactory.Instance.Create(transportDocument);
}
private class TransportFactory : TransportFactory<BsonDocument>
{
public static readonly TransportFactory Instance = new TransportFactory();
protected override Transport Create(BsonDocument source, TransportBuilder builder)
{
return builder
.WithTransportId(new TransportId(source.GetString("transportId")))
.WithPersonCapacity(new PersonCapacity(source.GetInt("personCapacity")))
.Build();
}
}
}
The advantages of this approach:
The builder is responsible for building the domain object. This allows you to move some trivial validation out of the domain object, especially if the domain object doesn't expose any public constructors.
The factory is responsible for parsing the source data.
The domain object can focus on business rules. It's not bothered with parsing or trivial validation.
The abstract factory class defines a generic contract, which can be implemented for each type of source data you need. For example, if you need to interface with a web service that returns XML, you just create a new factory subclass:
public class TransportWebServiceWrapper
{
private class TransportFactory : TransportFactory<XDocument>
{
protected override Transport Create(XDocument source, TransportBuilder builder)
{
// Construct domain object from XML.
}
}
}
The parsing logic of the source data is close to where the data originates, i.e. the parsing of BSON documents is in the repository, the parsing of XML is in the web service wrapper. This keeps related logic grouped together.
Some disadvantages:
I haven't tried this approach in large and complex projects yet, only in small-scale projects. There may be some difficulties in some scenarios I haven't encountered yet.
It's quite some code for something seemingly simple. Especially the builders can grow quite large. You can reduce the amount of code in the builders by converting all the WithXxx() methods to simple properties.
A better approach to handling this now is using MapCreator (which was possibly added after most of these answers were written).
e.g. I have a class called Time with three readonly properties: Hour, Minute and Second. Here's how I get it to store those three values in the database and to construct new Time objects during deserialization.
BsonClassMap.RegisterClassMap<Time>(cm =>
{
cm.AutoMap();
cm.MapCreator(p => new Time(p.Hour, p.Minute, p.Second));
cm.MapProperty(p => p.Hour);
cm.MapProperty(p => p.Minute);
cm.MapProperty(p => p.Second);
}
Niels has an interesting solution but I propose a much different approach:
Simplify your data model.
I say this because you are trying to convert RDBMS style entities to MongoDB and it doesnt map over very well, as you have found.
One of the most important things to think about when using any NoSQL solution is your data model. You need to free your mind of much of what you know about SQL and relationships and think more about embedded documents.
And remember, MongoDB is not the right answer for every problem so try not to force it to be. The examples you are following may work great with standard SQL servers but dont kill yourself trying to figure out how to make them work with MongoDB - they probably dont. Instead, I think a good excercise would be trying to figure out the correct way to model the example data with MongoDB.
Consider NoRM, an open-source ORM for MongoDB in C#.
Here are some links:
http://www.codevoyeur.com/Articles/20/A-NoRM-MongoDB-Repository-Base-Class.aspx
http://lukencode.com/2010/07/09/getting-started-with-mongodb-and-norm/
https://github.com/atheken/NoRM (download)