How to automatically set properties on view model with StructureMap - c#

I have an interface ITranslateStuff and a static class and method with a generic parameter that is constrained (where class, ITranslateStuff, new()).
string translation = Translator.TranslateStuff<ITranslateStuff>();
Depending on which implementation of ITranslateStuff that I pass the method returns a different string.
I have ViewModels with a lot of different properties wich returns implementations of ITranslateStuff, for example:
public class ExampleViewModel
{
public string OtherStuff {get; set; }
public string TranslateStuffExample1 Translations { get; set; }
public ExampleViewModel2 SubModel {get; set; }
}
public class ExampleViewModel2
{
public string MoreStuff { get; set; }
public string TranslateStuffExample2 Translations { get; set; }
}
where both DoStuffExample1 and DoStuffExample2 implements ITranslateStuff.
I'm currently populating all theese properties with code like this:
model.Translations = Translator.TranslateStuff<TranslateStuffExample1>();
model.SubModel.Translations = Translator.TranslateStuff<TranslateStuffExample2>();
In the project we use StructureMap. I want to avoid setting all the properties on my view model manually with the same static method call. I have an ActionFilter where I set common properties on my view model, and was thinking I want to do this in an action filter as well.
I've tried finding something in StructureMap that can do this for me.
How can I solve this?

You will want to use 'setter injection'.
http://docs.structuremap.net/ConstructorAndSetterInjection.htm#section4

Related

Generic Property and IoC (Autofac) Issues

Im doing an MVC 5 proyect using DI with IoC (Autofac) and the use of Generic Repository for the Data access part.
Now, my controller have an interface as a property injected to it called IProg_II_ModelFactory, this is the concrete class in question:
public class Prog_II_ModelFactory : IProg_II_ModelFactory
{
#region Fields
private readonly IGenericRepository<T> _genericRepository;
#endregion
#region Ctor
public Prog_II_ModelFactory(
IGenericRepository<T> genericRepository
)
{
_genericRepository = genericRepository;
}
#endregion
#region Methods
public Prog_II_Model SetProgIIModelStartUp()
{
var model;
model.FillList = _genericRepository.GettAll();
//Other things to be filled.
return model;
}
}
And my controller is injecting the interface of this class, here is the controller:
public class HomeController : Controller
{
private readonly IProg_II_ModelFactory _prog_II_ModelFactory;
public HomeController(
IProg_II_ModelFactory prog_II_ModelFactory
)
{
_prog_II_ModelFactory = prog_II_ModelFactory;
}
public ActionResult Index()
{
var model = _prog_II_ModelFactory.SetProgIIModelStartUp();
return View(model);
}
}
The problem with this is that Prog_II_ModelFactory must be generic (Prog_II_ModelFactory<T> where T : class)
The problem with this is that, it wont stop there, then it will ask me that the controller should also be generic and on top of that as Im using Autofac, the partial class to for the binding must be generic too and the App_Start itself!.
Is there any way I can use the Generic Interface of My repository without to flow TEntity all the way to App_Start ?
I read that I can use a method? but a lot of people is against this.
Edit:
Maybe instead of the property being Out of T, I have to type it?
for example:
#region Fields
private readonly IGenericRepository<Student> _genericRepository_Student;
private readonly IGenericRepository<Teacher> _genericRepository_Teacher;
#endregion
#region Ctor
public Prog_II_ModelFactory(
IGenericRepository<Student> genericRepository_Student,
IGenericRepository<Teacher> genericRepository_Teacher
)
{
_genericRepository_Student = genericRepository_Student;
_genericRepository_Teacher = genericRepository_Teacher;
}
#endregion
This means I cant do it at runtime, I have to know to which entity at compile time, what if I have 20 tables.
Edit 2:
This is my Model:
namespace Prog_II.Models
{
public class Prog_II_Model
{
#region Fields
public StudentModel Student{ get; set; }
public List<TurnModel> Turns{ get; set; }
public List<CarrerModel> Carrers { get; set; }
public List<StudentModel> Students{ get; set; }
#endregion
#region Ctor
public Prog_II_Model(){}
#endregion
}
public class StudentModel
{
#region Fields
public string Name { get; set; }
public string LastName{ get; set; }
public string NumberId { get; set; }
public string Carrer { get; set; }
public string Turn { get; set; }
#endregion
}
public class TurnModel
{
public string Description{ get; set; }
}
public class CarrerModel
{
public string Description{ get; set; }
}
}
And sure enough I pass a Prog_II_Model in my view:
#using Prog_II.Models
#model Prog_II_Model
public HomeController(Prog_II_ModelRepository modelRepository)...
public class Prog_II_ModelRepository()
{
IGenericRepository<Student> _genericRepository_Student; // get from somewhere
public Prog_II_Model GetModel()
{
var model = new Prog_II_Model();
model.Student = _genericRepository_Student.Get(); // some student
// put the rest of data into your huge all-encompassing model
return model;
}
}
That's just the idea - if you put all your data in a single model object, type-specific repositories are useful inside this single model repo, but it itself has no need to be generic (as opposed to general :)
I think there's something wrong with this One Huge Model approach, but YMMV.
Is your HomeController supposed to handle multiple entity types (Student, Teacher, Janitor, Dog, Cat, ...)? Is your Model flexible enough to handle all and any of them? If yes, use a non-generic repository interface, returning an object or some base entity type. If no, and you have different models per entity type (Dog has Color and Student has Scores), then your domain model asks for controller-per-entity type, inherited, as you said, from a generic controller type.
I don't see any reason for App_Start to be generic.

Model or ViewModel when representing a subset of data in MVVM?

If I have a complex model representing a large amount of data, and I only wish to display a cut-down version of that model (e.g. Name, Description), what is the best approach in MVVM?
Most solutions I can find seem to assume that the data is already present in memory and recommend using a new ViewModel that exposes only the fields required.
However rather than select out all of the data from the database, it would be preferable to select just what is necessary. Do I then create a new model to hold that data? Selecting directly into the ViewModel is possible but feels like the wrong thing to do. Likewise using a new model to represent a different version of the same data also feels off somehow.
What is the accepted method of doing this?
As a simple example (Simple enough class that I wouldn't ordinarily do this):
public class User {
public int UserID {get;set;}
public string FirstName
public string LastName
public int AccessLevelID
public List<Groups> UserGroups
}
but I only really need:
public class PreviewUser {
int UserID
string FirstName
}
You can create another type with is a subset of the business type.
usually this is known as a
DTO - Data transfer Object which encapsulates only what you need. so the database needs to query only the subset of the entity.
public class UserDto
{
public int ID { get;set;}
public string Name{ get;set;}
}
Secondly if you need to add some ui logic to the display it is common to wrap the specific DTO in a more specific UI model.
public class UserUI
{
UserDTO _userDto;
UserUI(UserDTO userDto)
{
_userDto = userDto;
}
public string Name
{
get{return IsAfter_21_hours ? "The user as gone home" : _userDto.Name;}
}
}
the UserViewModel will reference an instance of UserUI.
You can either remove properties you don't need from the model (to slightly improve performance) or you can create a viewmodel that will provide only properties that you want to show.
Here is an example:
public class UserViewModel
{
private readonly User _user;
public UserViewModel(User user)
{
_user = user;
}
public int UserID
{
get { return _user.UserID; }
}
public string FirstName
{
get { return _user.FirstName; }
}
}
...
var viewModels = userRepository.GetUsers().Select(user => new UserViewModel(user));
UPDATED:
If performance is really important for you, you can use inheritance. Base class will be smaller version of the data and derived class will contain complete data. You can use the base class when you need to get only some fields from DB and save bandwidth.
public class BaseUser
{
public int UserID { get; set; }
public string FirstName { get; set; }
}
public class User : BaseUser
{
public string LastName { get; set; }
public int AccessLevelID { get; set; }
public List<Groups> UserGroups { get; set; }
}
There are number of approaches you may use:
use "full version" of source model. Since you're building UI, the user will see only what you want to display;
use view model, and wrap source model into this view model. The implementation is trivial, and amount of data is limited before UI;
use view model, and copy data from source model into this view model. The implementation is more complex (either mapping from existing model, or loading only required data from database), but view model and model are totally decoupled.
Actually, it depends on what is more suitable for you.
Note, that often the difference between "view model" and "model" is blurred. If the model looks like this:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
...and view model - like this:
public class PersonViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
then throw this view model away. While there's no difference, you don't need to create extra classes.
I think you don't have to create new model class to hold user data for view . Instead create a view model class and map the model properties to VM. See the example below
public class UserViewModel
{
Public UserViewModel(User user)
{
//initialize required viewmodel properties here
}
int UserID {get;set;}
string FirstName{get;set;}
}

Config Automapper to ignore type when it's an inner-inner property but not inner property

This one takes a little explaining. I have a set of types such that;
public class Child
{
public int ID { get; set;}
}
public class MayHaveChild
{
public Child Value { get; set; }
public int MayID { get; set; }
}
public class MustNotHaveChild { get; set; }
{
public List<MayHaveChild> MayValues { get; set; }
}
In the above scenario, I want any mapping of MayHaveChild to have the values for the Child object, except when I have mapped MustNotHaveChild. E.g.;
When I have
//...some code
MayHave obj = Mapper.Map<MayHaveChild>(childObj);
// I want to be able to access obj.Child.ID
But when I have
//...some code
MustNotHave obj = Mapper.Map<MustNotHaveChild>(notHaveObj);
// I want to be able to access obj.MayValues[0].MayID but
// *not* obj.MayValues[0].Value
I've been through the automapper documention on nesting, polymorphism, lists, etc and I can't find anything that quite matches what I want.
I could solve this by having a inheriting the MayHave class to a MustNotHave variant but this would involve changing quite a lot of existing code. Is there a way to configure Automapper in the manner I need?
I couldn't find a way to configure AutoMapper the way I wanted without going down the inheritance route - though this proved less problematic than I thought. I did something like the following;
public class NoChild : MayHaveChild
{
}
public class MustNotHaveChild { get; set; }
{
// \/--datatype change here
public List<NoChild> MayValues { get; set; }
}
Then, later in the AutoMapper config;
Mapper.CreateMap<MayHave, NoChild>()
.ForMember(c => c.Child, opt => opt.Ignore());

Using base model class(es) without modifying it in asp.net mvc

Let's say I created a few models via Entity Framework, and one of them is called Paper_Results. This is how the class might look:
public partial class Paper_Results
{
public string Color { get; set; }
public int Height { get; set; }
public int Width { get; set; }
}
I want to use this class like a domain model. Now let's say I create a class the derives from Paper_Results with an added interface
public class Construction_Paper : Paper_Results, IMeasurementType
{
[Required]
public (new?) string Color { get; set; }
[Required]
[Range(1, Int32.MaxValue, ErrorMessage = "Value should be greater than or equal to 1")]
public (new?) int Height { get; set; }
[Required]
[Range(1, Int32.MaxValue, ErrorMessage = "Value should be greater than or equal to 1")]
public (new?) int Width { get; set; }
public virtual string MeasurementType
{
get { return "inches"; }
}
}
Now when I create my ViewModel, I'll used the derived class instead:
public class Construction_Paper_ViewModel
{
Construction_Paper cp;
List<Construction_Paper> cpList;
string title;
public Construction_Paper_ViewModel()
{
title = "Construction Paper";
cp = new Construction_Paper();
cpList = new List<Construction_Paper>();
}
}
I know I should be using uint instead of int for non-negative integers, but I just wanted to add more data annotations to the code. What I'm asking is what is the best OOP technique to derive from Paper_Result class, so that I don't have to modify it at all. The reason is because if I create a new solution and/or project, I don't want to do any modifications to it when I auto-regenerate it using Entity Framework. Should I use shadowing? Or the new keyword in the derived class? Or do you guys have any other better ideas?
The auto-generated EF models do not contain 'virtual' in their methods, thus the reason why I brought up shadowing and the new keyword.
First of all, not every problem should be addressed via inheritance.
Second, the .NET framework already has a mechanism to add metadata (attributes) to an existing object. These are called Buddy Classes, and use the MetadataTypeAttribute class.
The idea is that you add an attribute to the class that allows you to specify a different class that is used to define the metadata for the original class. It's not pretty, but it gets the job done.

Get custom property types using Reflection

Suppose I have a class (something like this):
public class User
{
public Guid Id { get; set;}
public DateTime CreationDate { get; set; }
public string Name { get; set; }
public UserGroup Group { get; set; }
}
Is there a way get all property types that are not part of the .NET Framework.
So in this case I want to get only UserGroup ? Is that possible ?
The best thing I can come up with is something like:
IEnumerable<Type> types = typeof(User).GetProperties().Where(p => !p.PropertyType.Namespace.StartsWith("System.")).Select(t => t.PropertyType);
But this looks like a hack-job. Sorry if dup, couldn't find anything like that, and sorry for the formatting, did my best.
I think what you have is probably reliable enough for what you want. However, from a flexibility/readability point of view maybe it would be better to define your own attribute type which you could apply at property level i.e.
public class User
{
public Guid Id { get; set; }
public DateTime CreationDate { get; set; }
public string Name { get; set; }
[CustomProperty]
public UserGroup Group { get; set; }
}
You could then use reflection to query all the properties which have this attribute. This would give you the ability to include/exclude any properties.
Sorry I forgot to mention that I can't modify the domain entities. (can't add an attribute).
You can use the MetadataType to add attributes to a base class e.g.
class UserMetadata
{
...
[CustomProperty]
public UserGroup Group { get; set; }
}
[MetadataType(typeof(UserMetadata)]
public class DomainUser : User
{
}
Reflection is always some kind of hacking, so yes, it FEELS like a hackjob.
But analyzing the entity, the class, will have to be done with reflection. So you are doing it the correct way.
One pitfall. You yourself are able to create your own types inside a namespace "System". That would mess up your search. You also could also analyze then Assembly of the property type, but then you have to know of all .NET assemblies, which is a big list.
What you have done is fine, you could do something like this however and make use of the Except method.
public static Type[] GetNonSystemTypes<T>()
{
var systemTypes = typeof(T).GetProperties().Select(t => t.PropertyType).Where(t => t.Namespace == "System");
return typeof(T).GetProperties().Select(t => t.PropertyType).Except(systemTypes).ToArray();
}
Your approach works. I would just throw in that you could also try to check the Assembly the type was defined in, and for example check if it was loaded from the global assembly cache.
bool wasLoadedFromAssemblyCache = typeof(T).Assembly.GlobalAssemblyCache;

Categories