stevejgordon
stevejgordon

Reputation: 447

Circular Dependancy on Interface

I'm in the process of re-factoring and structuring a Win8 App Solution. I've been separating out my key components into their own projects. I have:

So far I've got things working but have one case where I can't work out the best structure. Within my ViewModels project I have a data mapper class. Basically it takes in a model and spits out a view model. I've been trying to move this to the service layer and created an Interface for it but ran into a dependency within the Interface for knowledge of the ViewModel classes, so have essentially a circular dependency at the moment.

EDIT: I should explain that the ViewModels themselves need to utilise this mapper. For example I have an overall PageViewModel which holds everything the XAML page requires. One of these things is a list of VehicleViewModels which is a list of vehicles that contains some view specific properties. So the PageViewModel will call into the data service, get a Vehicle model and then use the mapper to turn this into the VehicleViewModel.

Here is the interface.

namespace MyApp.Contracts
{
    public interface IDataMapperService
    {
        VehicleViewModel VehicleToVehicleViewModel(Vehicle v);
        TripViewModel TripToTripViewModel(Trip t);
    }
}

As you can see, I want to return a ViewModel object from the two methods. However the ViewModel project already has a reference to this Contracts project, so I this currently won't build.

I toyed with the idea of creating and Interface for the viewmodels but then I'd have lots of work to create the interfaces and I'm not sure that's the best way. Have I overlooked something obvious here?

EDIT: Here's an actual implementation of the current Interface:

 public VehicleViewModel VehicleToVehicleViewModel(Vehicle v)
    {
        var newVehicle = new VehicleViewModel(v.VehicleID, v.Make, v.Model, v.Petrol, v.Registration);

        foreach (Trip t in v.Trips)
        {
            newVehicle.Trips.Add(TripToTripViewModel(t));
        }

        IQueryable<Trip> trips = v.Trips.AsQueryable();

        var now = DateTime.Now.Date;

        var firstofmonth = new DateTime(now.Year, now.Month, 1);

        while (now.DayOfWeek != DayOfWeek.Monday) now = now.AddDays(-1);

        var weektrips = from t in trips
                        where t.Date >= now
                        select t;

        var monthtrips = from t in trips
                         where t.Date >= firstofmonth
                         select t;

        newVehicle.TripsThisWeek = weektrips.Count();
        newVehicle.MilesThisWeek = (int)Math.Round(weektrips.Sum(t => t.Mileage), 0);
        newVehicle.TripsThisMonth = monthtrips.Count();
        newVehicle.MilesThisMonth = (int)Math.Round(monthtrips.Sum(t => t.Mileage), 0);

        return newVehicle;
    }

    public TripViewModel TripToTripViewModel(Trip t)
    {
        var newTrip = new TripViewModel(t.TripID, t.Date, t.Mileage);
        return newTrip;
    }

Upvotes: 0

Views: 129

Answers (2)

Jeff-Meadows
Jeff-Meadows

Reputation: 2184

You could use generics to create your mapper interface.

namespace MyApp.Contracts
{
    public interface IDataMapperService<ViewModelT, ModelT>
    {
        ViewModelT ModelToViewModel(ModelT v);
    }
}

Your service could then return an IDataMapperService<VehicleViewModel, Vehicle> and an IDataMapperService<TripViewModel, Trip>. You could create lightweight interfaces for view models and models to use with generic constraints.

namespace MyApp.Contracts
{
    public interface IModel {}
    public interface IViewModel {}

    public interface IDataMapperService<ViewModelT, ModelT>
        where ViewModelT : IViewModel
        where ModelT : IModel
    {
        ViewModelT ModelToViewModel(ModelT v);
    }
}

Then, to implement your new interface, you'd create a mapper class.

public class DataMapperService : IDataMapperService<VehicleViewModel, Vehicle>
{
    public VehicleViewModel ModelToViewModel(Vehicle v)
    {
        //implementation goes here
    }
}

Obviously, you will need to implement this class in a project that references your contracts, models, and viewmodels projects.

Upvotes: 1

Robert
Robert

Reputation: 4406

If I am understanding the question correctly you are trying to map from one object to a view model. If this is the case writing your own mapper tool may not be super efficiant for your usage. Check out Automapper It will allow you to map one object to another type by calling the Mapper.Map() method.

It looks to me like you are over thinking what you actually want to accomplish. If you need a VehicleViewModel then map the vehicle to the VehicleViewModel and call your mapping method. Automapper makes doing this super easy. But in general you just need a go-between mapper that lives on whatever layer can access your view models and it does the mapping for the different types.

Upvotes: 0

Related Questions