I'm new to dependency injection but fast becoming a big fan. However I can't seem to find anything that satisfactorily describes how to deal with objects at run time which are not injected from a container. I'll refer to same as data objects.
Consider the following, (forgive me if the following shows I've completely missed the point of DI):-
In the old days I would code an object as follows: -
public class Person
{
public string Name { get; set; }
public string EmailAddress { get; set; }
public void DoSomething(params string[] paremeters)
{
//code to do something with this person using parameters
}
public void DoSomethingElse()
{
//code to do something else with this person
}
}
Now with DI I might do the following: -
public class Person
{
public string Name { get; set; }
public string EmailAddress { get; set; }
}
public interface IPersonService
{
void DoSomething(Person person, params string[] paremeters);
void DoSomethingElse(Person person);
}
public class PersonService : IPersonService
{
public void DoSomething(Person person, params string[] paremeters)
{
//code to do something with this person using parameters
}
public void DoSomethingElse(Person person)
{
//code to do something else with this person
}
}
And the IPersonService service would be 'injected' through constructors into any processes that needed it. The problem is that it feels wrong having to add a Person parameter to every procedure and method in the PersonService but no alternatives seem to work any better.
For example I could use something like
Person _person;
void Configure(Person person)
{
_person = person
}
..in all my injected services which needed transient data, but then you run into state problems and all such services need to be transient. Again not happy with that.
In this example the person might come from a database, a screen form, a file, have been selected from a list in a directory or anywhere else.
I am aware that I could inject my data using a data repository (class to access the data and all the CRUD stuff) and indeed I have every intention of doing that but that still doesn't solve the problem of how I tell the service, in this case, which person to access unless of course I add a procedure into the service which includes a parameter for the identity of the person and then use the repository to go and fetch the person... but that then works just like the Initialise approach which results in State problems. It also relies on remembering to call the procedure in the service to configure the data.
My question is, what's the best practise here? Please keep it simple.
Many thanks
Related
I am using Entity framework 5 and using repository pattern. Say I got these entities Customer, Files, Images, Tasks, Invoice, User.
Each entity (apart from Customer) has a foreign key of Customer. When a user logs in I store the customerid in session (aps.net mvc). What I want is any CRUD taken on all entities to be limited to the customer who's user is logged in. e.g I can't afford to delete a Task belonging to customer 1 to be deleted by user who is from customer 2.
Is adding an argument of customerid for each method of repositories the best way to achieve this or are there any better/clever ways of doing it?
Tricky to give a definitive answer but you could make it a bit more extensible by implementing higer order functions, like this:
public interface IRepository<T>
{
public T GetBy(Expression<Func<T, bool>> query)
}
public class FileRepository : IRepository<File>
{
public File GetBy(Expression<Func<T, bool>> query)
{
using(var context = new FilesContext())
{
return context.Files.Where(query).FirstOrDefault();
}
}
}
public class SomeController
{
private IRepository<File> _repo;
public SomeController(IRepository<File> repo)
{
_repo = repo;
}
public ActionResult Index()
{
var model = _repo.GetBy(f => f.CustomerId == Session.Whatever.CustomerId);
return View(model);
}
}
This way you can vary the search query when required, rather than tie yourself in to using a hardcoded customer id property. For example, if you wanted to get the File object by the FileID, not the CustomerID, then:
var model = _repo.GetBy(f => f.FileId == someId);
and that's the only part of the code that needs to change.
Some really good info on Higher Order functions and functional programming in C# here: http://www.codeproject.com/Articles/375166/Functional-programming-in-Csharp
Edit:
You might be able to isolate the "Always use the customer ID when hitting DB" into a repository of it's own, using a decorator style pattern, thus: (massive disclaimer - I haven't tested this, but something along these lines should work)
public class SpecialFileRepo : IRepository<File>
{
private readonly IRepository<File> _baseRepo;
public SpecialFileRepo(IRepository<File> baseRepo)
{
_baseRepo = baseRepo;
}
public SpecialFileRepo() : this(new FileRepository())
{
}
public File GetBy(Expression<Func<File, bool>> query)
{
var parameters = query.Parameters;
var newParam = Expression.Parameter(typeof (File), "f");
var additionalQuery = Expression.AndAlso(query.Body,
Expression.Equal(
Expression.PropertyOrField(newParam, "CustomerId"),
Expression.Constant(HttpContext.Current.Session["customerId"])));
var newQuery = query.Update(additionalQuery, parameters);
return _baseRepo.GetBy(newQuery);
}
}
Then anything that's talking to a repository, as far as it's concerned, it's just a base repository, but this class is sitting in between and always grafting the "customerid = sessionwhatever" expression onto what finally gets passed to the database. And of course, anything that only cares about using the base repository, can still do so.
I wish to give a Person as defined below, the ability to print a vCard out of my system. To provide the user with privacy options, the user can select whether to show/hide certain properties. In it's simplest form, I need to have a separate table that would hold the user's choices.
I was wondering if it was possible to build this configurator table using reflection. As shown in the Person model below, I could decorate properties with a custom attribute, and then using those properties, construct and persist a model that would have a bool property for every decorated Person property.
public class Person
{
public string UserName { get; set; }
public string FirstName { get; set; }
[DisplayOnVCard]
public string LastName { get; set; }
[DisplayOnVCard]
public string Email { get; set; }
[DisplayOnVCard]
public string MobilePhone { get; set; }
}
** where [DisplayOnVCard] is a custom attribute.*
At the end of this, I expect a table in the db that would correspond to this:
public class VCardConfigurator
{
public bool LastName { get; set; }
public bool Email { get; set; }
public bool MobilePhone { get; set; }
}
This is just a sample representation of what is actually a huge entity. Which is why I hope to avoid manually mapping a bool field to each optional property.
I believe this problem domain is quite similar to how, for instance, privacy settings work on social networking sites, yes?
While I was typing this, I did ponder upon the possibility that if down the line I was to remove the attribute from one of the properties, what implications that might have. Needs some thought!
Further reading for self:
Programmatically adding properties to an MVC model at runtime
There is a huge possibility that I am galloping down a totally wrong path! If that is the case, please advice so!
#1 Update
I am not sure its possible to add or remove attributes for an instance since attributes are at the class level, but their property values can be changed (Since they are instances).
My suggested solusion
I am not sure what you mean in "I expect a table in the db that would correspond to this",
since you can't have a table in the database that contains only the columns of the non-privacy properties for each user.
You will need a dedicated table for this mapping (Lets say 'PrivacyMappings' table), with these columns:
UserId, PropertyName, IsPrivate.
When a user is added, all the properties will be added to this table with a default privacy settings (for instance, all properties are non-private by default).
You can add the properties by iterating over them and insert them as you said.
You can use the following class in entity framework:
public class PrivacyMapping
{
public int UserId {get;set;}
public string PropertyName {get;set;}
public bool IsPrivate {get;set;}
}
Adding the default privacy settings when a user being added:
// retrieve user model properties.
foreach (property in properties)
{
//iterrate over the user Properties.
context.PrivacyMapping.Add(new PrivacyMapping(user.userId, propertyName, isPrivate);
}
context.SaveChanges()
Now you can take all the user non-private properties by
context.PrivacyMapping.Where(p=>p.UserId == user.id && !IsPrivate).Select(p=>p.PropertyName);
And now you can deal with information any way you want.
For example, you can have a VCardItems class, that receive an user id/object in its c'tor and stores a dictionary of the allowed properties by their names.
public class VCardItems{
private Dictionary<string, object> properties{get;set;}
public VCardItems(User user)
{
// initiate values..
}
public object this[string name] {
get
{
if (properties.ContainsKey(name))
{
return properties[name];
}
// A private property.
return null;
}
set
{
properties[name] = value;
}
}
}
There is other options of how to use the data, for example with ActionFilter that in this case sets the private properties to null or storing the non-private data in the HttpContext.Items dictionary,
but it really up to you.
First message
Before we get into details, I wonder how you expect to use this class.
If a view (or whatever going to handle it), going to receive have a runtime-generated class for example, how you gonna handle it?
How you gonna know what properties this model has?
Assume we have POCO class for Entity Framework 4:
public class Order
{
public long Id { get; set; }
public ISet<OrderItem> OrderItems { get; set; }
}
And this method to retrieve the order from database:
public Order GetOrder(long orderId)
{
using (var context = new MyModelEntities())
{
return context.Orders.Include("OrderItems").Where(order => order.Id == orderId).FirstOrDefault();
}
}
So suppose we do this:
Order myOrder = GetOrder(1);
Is myOrder.OrderItems a HashSet or SortedSet? Is there a way to control this?
Good question.
As far as i know (and there is no MSDN/blog/article i am aware of that dispells/proves this), a navigational property can be of any type as long as it implements ICollection<T>.
Both HashSet<T> and SortedSet<T> implement ICollection<T>, so either would be viable candidates.
Did you step through the code? You should be able to see which concrete class get's resolved.
Most people use ICollection<T> / IList<T>. Why are you wanting to declare the property as ISet<T>?
Why don't you just declare which type you want, instead of the interface.
Or you could try using dependency injection (For<ISet>().Use<HashSet>()).
I'm still learning, but with the stackoverflow commnuties help, I've been able to get closer and closer.
What I have right now is a View "Index.aspx":
System.Web.Mvc.ViewPage<Data.Models.GetDealsModel>
The Model:
public class GetDealsModel
{
// set up the model
public string DealId { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Logo { get; set; }
public string Website { get; set; }
public string TotalRows { get; set; }
}
And the controller:
public ActionResult Index()
{
LinqToDealsDataContext db = new LinqToDealsDataContext();
XElement xmlTree = XElement.Parse("<Request><ZipCode>92612</ZipCode></Request>");
var deals = db.spSearchDeals(xmlTree);
return View(deals);
}
And with this configuration I'm now getting this error:
The model item passed into the dictionary is of type 'System.Data.Linq.SqlClient.SqlProvider+SingleResult`1[Data.Models.spSearchDealsResult]', but this dictionary requires a model item of type 'Data.Models.GetDealsModel'.
I'm guessing that there's an issue connecting my Controller to my Model... I'm not sure why. PLEASE help me connect this final peice.
NOTE: I do understand that eventually I should separate my logic in the controller into a Repository Pattern, but for now, this will do.
You need to translate the data coming back from this call:
var deals = db.spSearchDeals(xmlTree);
into a GetDealsModel type. So something like:
GetDealsModel dealsModel = new GetDealsModel()
{
DealId = deals.DealId,
StreetAddress = deals.StreetAddress,
....
};
return View(dealsModel);
The reason being that your View is strongly typed to take a GetDealsModel, but your deals variable is not of that type and it gives you that exception when you pass it to the View.
You should create object of type GetDealsModel, but your DB Query returns object of type Data.Models.spSearchDealsResult. Try something like:
return new GetDealsModel
{
DealId = deals.Id,
// other fields here
}
Add to your learning curve list the following items:
Repository Pattern
Ask yourself the following question: Why do I need a service layer?
Read Steven Sanderson's book. It teaches you to think in MVC.
The above applies to your problems because your issues are clearly related to having code in your Controllers that should be in your Model (ie, data access code should be in a repository class). Ie, you are not thinking in MVC.
Your model should include the necessary repository classes, eg, DealRepository.
You need a Service class to map the objects your repository digs out of your database to your model class: that way conversion problems are encapsulated into the Service Layer code.
If you do this, you can then write in your controller:
public ActionResult Index()
{
return(DealService.GetByZipcode(92612));
}
Where DealService.GetByZipcode basically just maps DealRepository.GetByZipcode(92612) to your model class and returns the mapping result.
The DealRepository.GetByZipcode method would be roughly:
public static DealEntity GetByZipcode(string zip)
{
LinqToDealsDataContext db = new LinqToDealsDataContext();
XElement xmlTree = XElement.Parse("<Request><ZipCode>" + zip + "</ZipCode></Request>");
var deals = db.spSearchDeals(xmlTree);
return deals;
}
The DealEntity class is just whatever Linq gives you for your table.
The reason WHY for all this:
The reason for this structure is as follows:
a. All you data access code is in one place: DealRepository. You can test and debug that independently of everything else.
b. The mapping code is all in one place: DealService. You can test and debug that independently of everything else.
c. In other words, you need to properly separate your concerns.
The problem with your existing code is precisely that you have NOT separated concerns. Ie, you have taken a dash of MVC and put it in a food processor and ended up with mush full of problems that are way more difficult to deal with than they need be.
Your model is mixed into your controller, there is no repository, no service layer.
So hold your horses just a while and take the time to read Steve Sanderson's book.
I would also try modelling a simpler problem. That xml parsing makes my head hurt even on a good day.
NOTE:
You could seriously improve your naming conventions. LinqToDealsDataContext? You're kidding, right?
Description
My solution has these projects:
DAL = Modified Entity Framework
DTO = Data Transfer objects that are able to validate themselves
BL = Business Layer Services
WEB = presentation Asp.net MVC application
DAL, BL and WEB all reference DTO which is great.
The process usually executes this way:
A web request is made to the WEB
WEB gets DTOs posted
DTOs get automagically validated via custom ActionFilter
validation errors are auto-collected
(Validation is OK) WEB calls into BL providing DTOs
BL calls into DAL by using DTOs (can either pass them through or just use them)
DTO Validation problem then...
My DTOs are able to validate themselves based on their own state (properties' values). But right now I'm presented with a problem when this is not the case. I need them to validate using BL (and consequently DAL).
My real-life example: User registers and WEB gets a User DTO that gets validated. The problematic part is username validation. Its uniqueness should be checked against data store.
How am I supposed to do this?
There's additional info that all DTOs implement an interface (ie. User DTO implements IUser) for IoC purposes and TDD. Both are part of the DTO project.
Impossible tries
I can't reference BL in DTO because I'll get circular reference.
Compilation error
I can't create an additional DTO.Val project that would reference partial DTO classes and implement their validation there (they'd reference BL + DTO).
Partial classes can't span assemblies.
Possible tries
Create a special ActionFilter that would validate object against external conditions. This one would be created within WEB project thus seeing DTO and BL that would be used here.
Put DTOs in BL and keep DTO interfaces as actual DTOs referenced by other projects and refactor all code to use interfaces instead of concrete classes.
Don't handle external dependant validation and let external dependencies throw an exception - probably the worst solution to this issue
What would you suggest?
I would suggest an experiment that i have only been trialling for the last week or so.
Based on this inspiration i am creating DTOs that validate a little differently to that of the DataAnnotations approach. Sample DTO:
public class Contact : DomainBase, IModelObject
{
public int ID { get; set; }
public string Name { get; set; }
public LazyList<ContactDetail> Details { get; set; }
public DateTime Updated { get; set; }
protected override void ConfigureRules()
{
base.AddRule(new ValidationRule()
{
Properties = new string[] { "name" },
Description = "A Name is required but must not exceed 300 characters in length and some special characters are not allowed",
validator = () => this.Name.IsRequired300LenNoSpecial()
});
base.AddRule(new ValidationRule()
{
Properties = new string[] { "updated" },
Description = "required",
validator = () => this.Updated.IsRequired()
});
}
}
This might look more work than DataAnnotations and well, that's coz it is, but it's not huge. I think it's more presentable in the class (i have some really ugly DTO classes now with DataAnnotations attributes - you can't even see the properties any more). And the power of anonymous delegates in this application is almost book-worthy (so i'm discovering).
Base class:
public partial class DomainBase : IDataErrorInfo
{
private IList<ValidationRule> _rules = new List<ValidationRule>();
public DomainBase()
{
// populate the _rules collection
this.ConfigureRules();
}
protected virtual void ConfigureRules()
{
// no rules if not overridden
}
protected void AddRule(ValidationRule rule)
{
this._rules.Add(rule);
}
#region IDataErrorInfo Members
public string Error
{
get { return String.Empty; } // Validation should call the indexer so return "" here
} // ..we dont need to support this property.
public string this[string columnName]
{
get
{
// get all the rules that apply to the property being validated
var rulesThatApply = this._rules
.Where(r => r.Properties.Contains(columnName));
// get a list of error messages from the rules
StringBuilder errorMessages = new StringBuilder();
foreach (ValidationRule rule in rulesThatApply)
if (!rule.validator.Invoke()) // if validator returns false then the rule is broken
if (errorMessages.ToString() == String.Empty)
errorMessages.Append(rule.Description);
else
errorMessages.AppendFormat("\r\n{0}", rule.Description);
return errorMessages.ToString();
}
}
#endregion
}
ValidationRule and my validation functions:
public class ValidationRule
{
public string[] Properties { get; set; }
public string Description { get; set; }
public Func<bool> validator { get; set; }
}
/// <summary>
/// These extention methods return true if the validation condition is met.
/// </summary>
public static class ValidationFunctions
{
#region IsRequired
public static bool IsRequired(this String str)
{
return !str.IsNullOrTrimEmpty();
}
public static bool IsRequired(this int num)
{
return num != 0;
}
public static bool IsRequired(this long num)
{
return num != 0;
}
public static bool IsRequired(this double num)
{
return num != 0;
}
public static bool IsRequired(this Decimal num)
{
return num != 0;
}
public static bool IsRequired(this DateTime date)
{
return date != DateTime.MinValue;
}
#endregion
#region String Lengths
public static bool IsLengthLessThanOrEqual(this String str, int length)
{
return str.Length <= length;
}
public static bool IsRequiredWithLengthLessThanOrEqual(this String str, int length)
{
return !str.IsNullOrTrimEmpty() && (str.Length <= length);
}
public static bool IsRequired300LenNoSpecial(this String str)
{
return !str.IsNullOrTrimEmpty() &&
str.RegexMatch(#"^[- \r\n\\\.!:*,#$%&""?\(\)\w']{1,300}$",
RegexOptions.Multiline) == str;
}
#endregion
}
If my code looks messy well that's because i've only been working on this validation approach for the last few days. I need this idea to meet a few requirements:
I need to support the IDataErrorInfo interface so my MVC layer validates automatically
I need to be able to support complex validation scenarios (the whole point of your question i guess): I want to be able to validate against multiple properties on the same object (ie. StartDate and FinishDate); properties from different/multiple/associated objects like i would have in an object graph; and even other things i haven't thought of yet.
I need to support the idea of an error applying to more than one property
As part of my TDD and DDD journey i want my Domain Objects to describe more my 'domain' than my Service layer methods, so putting these complex conditions in the model objects (not DTOs) seems to achieve this
This approach i think will get me what i want, and maybe you as well.
I'd imagine if you jump on board with me on this that we'd be pretty 'by ourselves' but it might be worth it. I was reading about the new validation capabilities in MVC 2 but it still doesn't meet the above wish list without custom modification.
Hope this helps.
The S#arp Architecture has an [DomainSignature] method identifier that used with the class level validator [HasUniqueDomainSignature] will do the work. See the sample code below:
[HasUniqueDomainSignature]
public class User : Entity
{
public User()
{
}
public User(string login, string email) : this()
{
Login = login;
Email = email;
}
[DomainSignature]
[NotNullNotEmpty]
public virtual string Login { get; set; }
[DomainSignature]
public virtual string Email { get; set; }
}
Take a closer look at http://www.sharparchitecture.net/
I had this exact same problem and after trying to find a work around for days and days and days, I ended up merging my DTO, DAL, and BL into one library. I kept my presentation layer separate.
Not sure if that is an option for you or not. For me, I figured that my chances of ever changing the data store were very slight, and so the separate tier wasn't really needed.
I also have implemented the Microsoft Validation Application Block for all my DTO validations. They have a "Self Validation" method that lets you perform complex validations.
Resulting solution
I ended up using controller action filter that was able to validate object against external factors that can't be obtained from the object itself.
I created the filter that takes the name of the action parameter to check and validator type that will validate that particular parameter. Of course this validator has to implement certain interface to make it all reusable.
[ValidateExternalFactors("user", typeof(UserExternalValidator))]
public ActionResult Create(User user)
validator needs to implement this simple interface
public interface IExternalValidator<T>
{
bool IsValid(T instance);
}
It's a simple and effective solution to a seemingly complex problem.