I'm trying to get Property Injection working on a Custom Action Filter Attribute. It is working as it is supposed to, however, I'd like to use DI on the Property itself. My filter looks like this
[AttributeUsage(AttributeTargets.Class)]
public sealed class HeaderFilterAttribute : ActionFilterAttribute
{
public IMarketService MarketService
{ get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var view = (ViewResultBase)filterContext.Result;
if (view != null)
{
BaseViewModel viewModel = view.ViewData.Model as BaseViewModel;
if (viewModel != null)
viewModel.Header = GetHeaderScript();
}
base.OnActionExecuted(filterContext);
}
private string GetHeaderScript()
{
//Use MarketService here and return header script
return "script";
}
}
This is how I'm configuring the property using StructureMap inside my BootStrapper class.
//HeaderFilterAttribute
IMarketRepository marketRepository = new SqlMarketRepository();
IMarketService marketService = new MarketService(marketRepository);
ObjectFactory.Container.Configure(r => r.ForConcreteType<HeaderFilterAttribute>().
Configure.WithProperty("MarketService").
EqualTo(marketService));
My problem is I do not have access to SqlMarketRepository since all my concrete types are injected via DI and I really don't want to use concrete types in my bootstrapper. So the ultimate question now is, how do I inject MarketService into the Filter attribute without resorting to the above? :)
In your ObjectFactory.Initialize() call, add the following line:
SetAllProperties(x => x.OfType<IMarketService>());
That will inject the configured IMarketService instance into any property of type IMarketService, on any object retrieved from the container.
I think you need a custom action invoker implementation that will resolve the filters. You can dig a Windsor sample out of my company's implementation (about 1/2 way down). There should be several more available online. I know I've seen some on this site.
PS. I noticed you're using a base view model to populate a header. I'd recommend using the ViewData[] collection with a static key instead of inheritance in your view model. :)
Related
I'm using FluentValidation for the first time. I had some basic validation working, but then I realized I would need to do some database retrieval for some more complicated validation. That required doing Dependency Injection so I could use the database service, and that leads me to my current state: Stuck. I cannot get this to work.
To simplify things, I'll pretend that my application is dealing with sports leagues and teams, because I figure that's an easier mental model than contracts, invoices, funding sources, vendors, and subcontractors. :-)
So, suppose I have a viewmodel for a sports league. Within that viewmodel there is a collection of viewmodels for the teams that are in that league.
I have a screen to edit a league. That same screen allows changes to some of the information about the teams that are in that league.
LeagueViewModel
The viewmodel for the league contains a List of viewmodels for the teams.
[FluentValidation.Attributes.Validator(typeof(LeagueValidator))]
public class LeagueViewModel
{
public string LeagueName { get; set; }
public DateTime SeasonBeginDate { get; set; }
public DateTime SeasonEndDate { get; set; }
public List<TeamViewModel> TeamViewModels { get; set; }
}
I've created a validator for the LeagueViewModel. Unfortunately, when I edit the league and click the submit button, I get this error message:
InvalidCastException: Unable to cast object of type 'TeamViewModel' to type 'LeagueViewModel'. at FluentValidation.ValidationContext.ToGenericT
Apparently it is attempting to validate the TeamViewModel using the LeagueValidator.
I have gone through many variations trying to figure out how to get this to work. Here's what I have at the moment.
Validator
public class LeagueValidator : AbstractValidator<LeagueViewModel>
{
private readonly ILeagueService _leagueService;
public LeagueValidator(ILeagueService leagueService)
{
_leagueService = leagueService;
RuleFor(x => x.SeasonEndDate)
.NotNull()
.GreaterThan(x => x.SeasonBeginDate)
.WithMessage("Season End Date must be later than Season Begin Date.");
}
}
(The LeagueService bit is in there because in the real code it needs to check against some database values, which it uses the service to retrieve.)
Note that the LeagueValidator doesn't have any validation rules for any fields in the List of TeamViewModels.
League Validator Factory
public class LeagueValidatorFactory : ValidatorFactoryBase
{
private readonly Container _container;
public LeagueValidatorFactory(Container container)
{
_container = container;
}
public override IValidator CreateInstance(Type validatorType)
{
return _container.GetInstance<LeagueValidator>();
}
}
Dependency Injector
We're using SimpleInjector for DI. As part of that existing setup, it is calling a method to register the services. Within that method I've added a call to this:
private static void RegisterValidators(Container container)
{
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
var leagueValidatorProvider =
new FluentValidationModelValidatorProvider(new LeagueValidatorFactory(container));
leagueValidatorProvider.AddImplicitRequiredValidator = false;
ModelValidatorProviders.Providers.Add(leagueValidatorProvider);
container.Register<LeagueValidator>();
}
Questions
How do I get this to work properly?
Why is it trying to use the LeagueValidator to validate the TeamViewModel?
Do I need to have a separate validator and validator factory for every view model?
Even those that don't have any validation rules?
How do I tell it which validator to use for which viewmodel?
I figure I must be misunderstanding something basic.
Edit
Steven's response below got me pointed in the right direction! After I made his suggested changes, I encountered another error. Once I got that fixed, it works! Here are the changes I made to get the code above working properly.
LeagueViewModel
I removed this line, as it isn't necessary.
[FluentValidation.Attributes.Validator(typeof(LeagueValidator))]
LeagueValidatorFactory
I renamed it to "ValidatorFactory", because it turns out there will only be one validator factory, regardless of how many validators I create. I then changed the CreateInstance method to this:
public override IValidator CreateInstance(Type validatorType)
{
if (_container.GetRegistration(validatorType) == null)
{
return null;
}
return (IValidator)_container.GetInstance(validatorType);
}
This no longer explicitly specifies the type of validator to get (which is why only one factory will be needed). To determine whether a validator for the given type is available, it does a call to GetRegistration, returning null if none is found.
This was important! For every viewmodel, it is going to try to find a validator. Without this null check, an InvalidCastException gets thrown.
Dependency Injector
Following Steven's suggestion, I replaced the container.Register line with this:
container.Register(typeof(IValidator<>), new[] { typeof(SimpleInjectorInitializer).Assembly });
That avoids the need to explicitly list each validator every time a new one is added.
And now it all works! Thanks very much for your help, Steven!
I'm unfamiliar with FluentValidation, but it seems your LeagueValidatorFactory is requesting the wrong type from the container, considering it is supplied with the type to validate.
Because of this, I'd expect your validation factory to look something like this:
public class LeagueValidatorFactory : ValidatorFactoryBase
{
private readonly Container _container;
public LeagueValidatorFactory(Container container) =>
_container = container;
public override IValidator CreateInstance(Type validatorType) =>
(IValidator)_container.GetInstance(validatorType);
}
What I can see from the FluentValidator source code, is that the validatorType is a closed-generic version of the IValidator<T> type, with the T being the actual type being validated. This means, that you will have to register the validators by their IValidator<T> interface. For instance:
container.Register<IValidator<LeagueViewModel>, LeagueValidator>();
This Configuration as Code (or explicit-register) model, where you register every validator explicitly using a line of code, might work fine if you have just a few validators, but this will typically result in a Composition Root that has to be updated frequently.
A better model, therefore, is to use Auto-Registration, where you register all IValidator<T> implementations, using reflection. Fortunately, you don't have to implement this yourself; Simple Injector has your back:
var validatorAssemblies = new[] { typeof(LeagueValidator).Assembly };
container.Register(typeof(IValidator<>), validatorAssemblies);
This makes sure that you never have to change your Composition Root when you just added a new validator (in that particular assembly).
With this setup, I see no reason why you should mark your view model with the FluentValidation.Attributes.ValidatorAttribute. If you can, please remove it, as it only causes untight coupling between your view model and the validator.
I've been using MVVM for WPF quite a while now but I've always been doing it this way:
ExampleView.xaml.cs (namespace: Example.Views)
public partial class ExampleView
{
public ExampleView()
{
InitializeComponent();
var viewModel = new ExampleViewModel();
DataContext = viewModel;
}
}
The ExampleView.xaml has no code concerning the ExampleViewModel except for bindings to properties.
ExampleViewModel.cs (namespace: Example.ViewModels)
public ExampleViewModel()
{
// No important code in here concerning this topic. Code here is only used in this class.
}
Below is a simplified MainWindowView.xaml.
<Window ...
xmlns:views="clr-namespace:Example.Views">
<Grid>
<views:ExampleView />
</Grid>
</Window>
The MainWindowView.xaml.cs is similar to the ExampleView.xaml.cs. The MainWindowViewModel.cs has no important code concerning this topic.
Lastly, the App.xaml contains the StartupUri="Views/MainWindowView.xaml".
If this is a good pattern or not, I got my application to work. Since the application is not maintainable by me alone anymore, 2-3 people are now working on it creating some problems. One person is doing the majority of the coding (ViewModels basically), one person is doing the GUI (Views) and one person is doing the "framework" coding. (Using "" because this is not really a framework but I can't think of a better word for it.)
Now, I'm the guy that is doing the framework coding and I've been reading up on several subjects like dependency injection and the code below is what I came up with using UnityContainer from Windows.
ExampleView.xaml.cs (namespace: Example.Views)
public partial class ExampleView
{
public ExampleView()
{
InitializeComponent();
}
}
The ExampleView.xaml has no code concerning the ExampleViewModel except for bindings to properties.
ExampleViewModel.cs (namespace: Example.ViewModels)
public string MyText { get; set; }
public ExampleViewModel(ILocalizer localizer)
{
MyText = localizer.GetString("Title");
}
Below is a simplified MainWindowView.xaml.
<Window ...
xmlns:views="clr-namespace:Example.Views">
<Grid>
<views:ExampleView DataContext="{Binding ExampleViewModel}" />
</Grid>
</Window>
The MainWindowView.xaml.cs is similar to the ExampleView.xaml.cs.
MainWindowViewModel.cs
ExampleViewModel ExampleViewModel { get; set; }
private readonly ILocalizer _localizer;
private readonly IExceptionHandler _exHandler;
public MainWindowViewModel(ILocalizer localizer, IExceptionHandler exHandler)
{
_localizer = localizer;
_exHandler = exHandler;
ExampleViewModel = new ExampleViewModel(localizer);
}
Lastly, the App.xaml does not contains the StartupUri="..." anymore. It's now done in App.xaml.cs. It's also here where the `UnityContainer is initialized.
protected override void OnStartup(StartupEventArgs e)
{
// Base startup.
base.OnStartup(e);
// Initialize the container.
var container = new UnityContainer();
// Register types and instances with the container.
container.RegisterType<ILocalizer, Localizer>();
container.RegisterType<IExceptionHandler, ExceptionHandler>();
// For some reason I need to initialize this myself. See further in post what the constructor is of the Localizer and ExceptionHandler classes.
container.RegisterInstance<ILocalizer>(new Localizer());
container.RegisterInstance<IExceptionHandler>(new ExceptionHandler());
container.RegisterType<MainWindowViewModel>();
// Initialize the main window.
var mainWindowView = new MainWindowView { DataContext = container.Resolve<MainWindowViewModel>() };
// This is a self made alternative to the default MessageBox. This is a static class with a private constructor like the default MessageBox.
MyMessageBox.Initialize(mainWindowView, container.Resolve<ILocalizer>());
// Show the main window.
mainWindowView.Show();
}
For some reason I need to initialize the Localizer and ExceptionHandler classes myself. The Localizer and ExceptionHandler constructors are found below. Both have constructors with all arguments that have a default value. Adding constructors without arguments like
public ExceptionHandler() : this(Path.Combine(Directory.GetCurrentDirectory(), "ErrorLogs", DateTime.Now.ToString("dd-MM-yyyy") + ".log")) { }
doesn't change a thing.
public Localizer(ResourceDictionary appResDic = null, string projectName = null, string languagesDirectoryName = "Languages", string fileBaseName = "Language", string fallbackLanguage = "en")
{
_appResDic = appResDic ?? Application.Current.Resources;
_projectName = !string.IsNullOrEmpty(projectName) ? projectName : Application.Current.ToString().Split('.')[0];
_languagesDirectoryName = languagesDirectoryName.ThrowArgNullExIfNullOrEmpty("languagesFolder", "0X000000066::The languages directory name can't be null or an empty string.");
_fileBaseName = fileBaseName.ThrowArgNullExIfNullOrEmpty("fileBaseName", "0X000000067::The base name of the language files can't be null or an empty string.");
_fallbackLanguage = fallbackLanguage.ThrowArgNullExIfNullOrEmpty("fallbackLanguage", "0X000000068::The fallback language can't be null or an empty string.");
CurrentLanguage = _fallbackLanguage;
}
public ExceptionHandler(string logLocation = null, ILocalizer localizer = null)
{
// Check if the log location is not null or an empty string.
LogLocation = string.IsNullOrEmpty(logLocation) ? Path.Combine(Directory.GetCurrentDirectory(), "ErrorLogs", DateTime.Now.ToString("dd-MM-yyyy") + ".log") : logLocation;
_localizer = localizer;
}
My big question now is if I'm approaching dependency injection correctly and if having several static classes that I initialize once are bad. Several topics I've read state that static classes are a bad-practice because of bad testability and tightly coupled code, but right now the tradeoffs of dependency injection are bigger than having static classes.
Doing dependency injection correctly would be a first step in having less tightly coupled code though. I like the approach with the static MyMessageBox I can initialize once and that it's globally available in the application. This is mainly for "easy usage" I guess cause I can simply call MyMessageBox.Show(...) instead of injecting this all the way down to the smallest element. I have a similar opinion about the Localizer and ExceptionHandler because these will be used even more.
A last concern I have is the following. Lets say I have a class with several arguments and one of the arguments is the Localizer (because this will be used in nearly any class). Having to add ILocalizer localizer every time
var myClass = new MyClass(..., ILocalizer localizer);
feels very annoying. This would push me towards a static Localizer I initialize once and having never to care about it anymore. How would this problem be tackled?
If you have a bunch of "Services" which are used in many classes, you can create a facade class which encapsulates the required services and inject the facade into your classes.
Advantage of doing so is, you can easily add other services to that facade and they'd be available in all other injected classes, without modifying the constructor parameters.
public class CoreServicesFacade : ICoreServicesFacade
{
private readonly ILocalizer localizer;
private readonly IExceptionHandler excaptionHandler;
private readonly ILogger logger;
public ILocalizer Localizer { get { return localizer; } }
public IExceptionHandler ExcaptionHandler{ get { return exceptionHandler; } }
public ILogger Logger { get { return logger; } }
public CoreServices(ILocalizer localizer, IExceptionHandler exceptionHandler, ILogger logger)
{
if(localizer==null)
throw new ArgumentNullException("localizer");
if(exceptionHandler==null)
throw new ArgumentNullException("exceptionHandler");
if(logger==null)
throw new ArgumentNullException(logger);
this.localizer = localizer;
this.exceptionHandler = exceptionHandler;
this.logger = logger;
}
}
Then you can pass it to your classes:
var myClass = new MyClass(..., ICoreServicesFacade coreServices);
(which you shouldn't do anyway when using Dependency Injection, you shouldn't use new keyword, except for factories and models).
As for your ILocalizer and IExceptionHandler implementations... if your ExceptionHandler requires the Localizer and the localizer requires the string parameter, you have two options, depending on if the file name needs to be determined at a later point at run time or only once during the Application initialization.
Important
Don't use optional constructor parameters if you want to use dependency injection. For DI, constructor parameters should declare the dependencies in constructor and constructor dependencies are always considered as mandatory (don't use ILocalizer localizer = null within the constructor).
If you only create the logfile during the Applications initialization, it's quite easy
var logFilePath = Path.Combine(Directory.GetCurrentDirectory(), "ErrorLogs", DateTime.Now.ToString("dd-MM-yyyy") + ".log");
var localizer = new Localizer(...);
var exceptionHandler = new ExceptionHandler(logFilePath, localizer);
container.RegisterInstance<ILocalizer>(localizer);
container.RegisterInstance<IExceptionHandler>(exceptionHandler);
Basically in your bootstrapper you instantiate and configure your Localizer and ExceptionHandler, then register it as instance with the container.
If for some reason, you need to determine the name of log filename or language at a later point (after Bootstrapper configuration & initialization), you need to use a different approach: You need a factory class.
The factory will be injected into your classes rather than the instance of ILocalizer/IExceptionHandler and create the instance of it when the parameters are known.
public interface ILocalizerFactory
{
ILocalizer Create(ResourceDictionary appResDic, string projectName);
}
public class ILocalizerFactory
{
public ILocalizer Create(ResourceDictionary appResDic, string projectName)
{
var localizer = new Localizer(appResDic, projectName, "Languages", "Language", "en");
return localizer;
}
}
Using the facade Example from above:
public class CoreServicesFacade : ICoreServicesFacade
{
private readonly ILocalizer localizer;
public ILocalizer Localizer { get { return localizer; } }
public CoreServices(ILocalizerFactory localizerFactory, ...)
{
if(localizer==null)
throw new ArgumentNullException("localizerFactory");
this.localizer = localizerFactory.Create( Application.Current.Resources, Application.Current.ToString().Split('.')[0]);
}
}
Caveats & tips
Move Default configuration outside of the classes itself
Don't use such code inside your Localizer/ExceptionHandler classes.
_appResDic = appResDic ?? Application.Current.Resources;
_projectName = !string.IsNullOrEmpty(projectName) ? projectName : Application.Current.ToString().Split('.')[0];
_languagesDirectoryName = languagesDirectoryName.ThrowArgNullExIfNullOrEmpty("languagesFolder", "0X000000066::The languages directory name can't be null or an empty string.");
_fileBaseName = fileBaseName.ThrowArgNullExIfNullOrEmpty("fileBaseName", "0X000000067::The base name of the language files can't be null or an empty string.");
_fallbackLanguage = fallbackLanguage.ThrowArgNullExIfNullOrEmpty("fallbackLanguage", "0X000000068::The fallback language can't be null or an empty string.");
CurrentLanguage = _fallbackLanguage;
This pretty much makes it untestable and puts the configuration logic in the wrong place. You should only accept and validate the parameters passed into the constructor and determine the values and fall backs in either a) factory's create method or b) inside your bootstrapper (if runtime parameters aren't required).
Don't use View-related type inside your interfaces
Don't use ResourceDictionary in your public interfaces, this will leak View knowledge into your ViewModels and require you to have a reference to the assembly containing View/Application related code (I know I used it above, based on your Locator constructor).
If you need it, pass it as constructor Parameter and implement the class in Application/View assembly, while having your Interface in your ViewModel assembly). Constructors are implementation detail, and can be hidden (by implementing the class in a different assembly which allows reference to the class in question).
Static classes are evil
As you already realized, static classes are bad. Inject them is the way to go. Your Application will most likely need a navigation too. So you can put Navigation (Navigate to a certain View), MessageBoxes (display an information) and opening of new Windows (a kind of navigation too) into either one service or a navigation facade (similar to above one) and pass all services related to navigation as a single Dependency into your objects.
Passing parameters to ViewModel
Passing parameters can be a bit of a pain in "home-brew" frameworks and you shouldn't pass parameters via ViewModel constructors (prevents DI from resolving it or forcing you to use a factory). Instead consider writing a navigation service (or using exiting framework). Prims has it solved pretty nicely, you got a navigation service (which will do the navigation to a certain View and it's ViewModel and also offers INavigationAware interface with NavigateTo and NavigateFrom methods, which are called when one navigates to a new view (one of this methods parameters can be used to provide parameters to the ViewModel) and when navigating from a ViewModel (i.e. to determine if navigating from a view is viable or to cancel the navigation if necessary, for example: Asking the user to save or discard the data before navigating to the other ViewModel).
But that's bit off-topic.
Example:
public class ExampleViewModel : ViewModelBase
{
public ExampleViewModel(Example2ViewModel example2ViewModel)
{
}
}
public class Example2ViewModel : ViewModelBase
{
public Example2ViewModel(ICustomerRepository customerRepository)
{
}
}
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel(ExampleViewModel example2ViewModel)
{
}
}
// Unity Bootstrapper Configuration
container.RegisterType<ICustomerRepository, SqlCustomerRepository>();
// You don't need to register Example2ViewModel and ExampleViewModel unless
// you want change their container lifetime manager or use InjectionFactory
To get an resolve instance of your MainWindowViewModel simply do
MainWindowViewModel mainWindowViewModel = container.Resolve<MainWindowViewModel>();
and Unity will resolve all other dependencies (it will inject ICustomerRepository into Example2ViewModel, then inject Example2ViewModel into ExampleViewModel and finally inject ExampleViewModel into your MainWindowViewModel and return an instance of it.
The catch is: You can't use the container inside your ViewModels (though using it in View's code-behind is okay in your use case. However it's better to use navigation Service or a ViewModel Locator within your XAML (see Prism on how they did it)) .
So you need a navigation service of a kind, if you need to do it from ViewModels.
I want to use EF 5 model validation to avoid duplicate values in the database, so I'm using a model class like this:
[Table("MeasureUnits")]
public class MeasureUnit : IValidatableObject
{
public int MeasureUnitId { get; set; }
public string Symbol { get; set; }
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
using (MeasureUnitRepository rep = new MeasureUnitRepository())
{
MeasureUnit measureUnit = rep.FindDuplicateBySymbol(this);
if (measureUnit != null)
yield return new ValidationResult(
"There is another unit with this symbol, you can't duplicate it",
new[] { "Symbol" });
}
}
The repository class creates the DbContext, implements IDisposable, has the logic to find the duplicate and it all works just as intended.
However, using the debugger I realized the validation is performed twice for every insert or update, so the repository (and DbContext) gets instantiated and disposed twice also.
Besides that, there is another DbContext living in the controller but just don't find the way to use it inside the model class, other than including the DbContext in the model's constructor, but I feel it's not the right solution.
Is there a better o "right" way to achieve this validation?
Thanks in advance.
When you have to go to the database then you need to use DbContext and DbContext has an Overridable method called ValidateEntity. See this article: Entity Framework Validation.
I put the code I use in another answer here
And more about how I've structured the validation in MVC here.
Also, instantiating a context inside your repository is likely to cause you grief. The repositories will need to share a context. You could treat the context as your unit of work and pass it into the repository in the constructor, or you could wrap the context in your own unit of work and pass that in.
You can use any IOC container available out there like Unity, Ninject, Autofac or StructureMap to inject your repository as a dependency.
This way you would be able to access the same object in the controller, your Validate method or wherever you need to use it.
Some of these IOC(Ninject for sure - look for 'request scope') containers are capable of integrating with ASP.NET MVC so that the dependency(your repository in that case) is created once per request and disposed when the request ends.
Example using Ninject:
You create a globally accessible(the design is up to you) ninject kernel
public static class NinjectKernel
{
public static IKernel Kernel = new StandardKernel();
static NinjectKernel()
{
Kernel.Bind<IMyRepository>().To<MyRepositoryImpl>().InRequestScope();
}
}
and a controller factory for MVC controllers
public class NinjectControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null ? null : (IController)NinjectKernel.Kernel.Get(controllerType);
}
}
You can then set your controller factory in Global.asax like this
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
and get the repository in your Validate method in a similar way it's done in the Controller factory.
I am not able to perform property injection into a custom data annotation validation attribute
public class CustomValidationAttribute : ValidationAttribute
{
public ILogger Logger { get; set; }
public CustomValidationAttribute(string keyPointer)
{ }
public override bool IsValid(object value)
{
// Implementation here
return true;
}
}
Now, on my MVC Application_Start method I have the following Autofac configuration:
// Autofac Ioc Container
var builder = new ContainerBuilder();
builder.RegisterType<Logger>().As<ILogger>().InstancePerHttpRequest();
builder.RegisterType<CustomValidationAttribute>()
.OnActivating(e =>
{
e.Instance.Logger = e.Context.Resolve<ILogger>();
});
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
I have also tried the autowiring capabilities:
builder.RegisterType<CustomValidationAttribute>().PropertiesAutowired();
I am guessing that the properties of an attribute on data annotations are resolved at compile time and are immune to runtime injection.
This methods works fine for MVC filter attributes but does not work for data annotation attributes.
Any help is really appreciated on alternate methods to make this work.
For reference, we had a problem with a ValidationAttribute which needed to do some database work using a Repository, which in turn used an Entity Framework DbContext.
Our problem was that the DbContext was being cached by the attribute. This led to the data it contained being stale which affected the result of the validation!
We fixed it by doing our Repository resolve inside an Autofac Lifetimescope declaration inside the IsValid method:
using Autofac;
...
public override bool IsValid(object value)
{
using (var lifetimeScope = MvcApplication.Container.BeginLifetimeScope())
{
var repo = lifetimeScope.Resolve<IMyRepo>();
// Do your validation checks which require the repo here
} // The repo will be released / disposed here
}
Just adding my solution here as I haven't found this solution documented for this problem anywhere else - perhaps it's just so obvious nobody else has been as dumb as me :)
You are correct in your analysis - Autofac has a mechanism to inject into Filter Attributes [which is achieved by not instantiating them as attributes and leans on facilities exposed MVC 3].
There is no such natural extension point applicable to Validation Attributes, and Autofac doesn't make any attempt to do so.
I ended up using a new validator and some reflection to set an instance of the property in the data annotation.
public class IocValidator : DataAnnotationsModelValidator<ValidationAttribute>
{
public IocValidator(ModelMetadata metadata, ControllerContext context,
ValidationAttribute attribute)
: base(metadata, context, attribute) { }
public override IEnumerable<ModelValidationResult> Validate(object container)
{
IEnumerable<PropertyInfo> props =
from p in Attribute.GetType().GetProperties()
where p.CanRead
&& p.CanWrite
&& (p.PropertyType.IsInterface || p.PropertyType.IsAbstract)
select p;
foreach (PropertyInfo prop in props)
{
var instance = IocHelper.Resolver.GetService(prop.PropertyType);
if (instance != null)
prop.SetValue(Attribute, instance, null);
}
return base.Validate(container);
}
}
Then in my Application_Start I registered my new validator adapter as such:-
DataAnnotationsModelValidatorProvider.RegisterDefaultAdapter(typeof(IocValidator));
There are definite performance implications on this approach and the dependence of the IocHelper in the Validator (ohh, the irony, dependency on the dependency injection container).
Any thoughts or better approaches are quite welcomed.
I solved it a bit differently (you're still wiring stuff via ValidationAttributes) in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));
I need some help - I am trying to use a custom validation attribute in an ASP.NET MVC web project that needs to make a database call.
I have windsor successfully working for the controllers and the IRepository interface is injected normally. The problem arrises when I need to inject the repository into the attribute class.
The attribute class has the following code:
public class ValidateUniqueUrlNodeAttribute : AbstractValidationAttribute
{
private readonly string message;
private readonly IArticleRepository articleRepository;
public ValidateUniqueUrlNodeAttribute(string message)
{
this.message = message;
}
public ValidateUniqueUrlNodeAttribute(string message, IArticleRepository articleRepository):this(message)
{
this.articleRepository = articleRepository;
}
public override IValidator Build()
{
var validator = new UniqueUrlNodeValidator(articleRepository) { ErrorMessage = message };
ConfigureValidatorMessage(validator);
return validator;
}
My problem is that I cannot seem to make Windsor intercept the contruction of the attribute to pass in the IArticleRepository
The current code in my global.asax file is as follows:
container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
container
.RegisterControllers(Assembly.GetExecutingAssembly())
.AddComponent<IArticleRepository, ArticleRepository>()
.AddComponent<ValidateUniqueUrlNodeAttribute>();
Any help would be greatly appreciated.
AFAIK no dependency injection container can directly manage an attribute, since it's instantiated by the runtime and there's no way to intercept that.
However, they can cheat by either:
Using a static gateway to the container (example), or
Using a "BuildUp" feature that injects whatever dependencies are found within an already-constructed object. This is called BuildUp in Unity or InjectProperties in Autofac.
Windsor doesn't support #2 (ref1, ref2), so you can either:
Try one of the hacks to make Windsor support #2 (hack1, hack2)
Use a static gateway
Implement your own IValidatorBuilder and make it use Windsor to create validators. I'm sure this is implemented somewhere but I can't find it right now...
Don't know if this helps, but I subclassed ValidationAttribute to expose a Resolve<T>() method like so:
public abstract class IocValidationAttribute : ValidationAttribute
{
protected T Resolve<T>()
{
return IocHelper.Container().Resolve<T>();
}
}
Then it can be used in any custom ValidatorAttribute that needs to hit a database:
public class UniqueEmailAttribute : IocValidationAttribute
{
public override bool IsValid(object value)
{
ICustomerRepository customerRepository = Resolve<ICustomerRepository>();
return customerRepository.FindByEmail(value.ToString()) == null;
}
}
I think it's a variation of the 'Static Gateway' approach mentioned by Mauricio Scheffer. I don't know if this is a good design or not. I'm not a huge fan of it, I'd rather the dependency was injected more 'elegantly', though I can't use constructor injection obviously, I'd like to use Property injection but can't work out a way to hook into the ASP.NET MVC framework code to do this (I've even pored though the MVC2 source code).
I was able to wire it up [using Autofac as it happens, but it's just constructor injection via the ASP.NET MVC DependencyResolver] in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));
Hmm.
Can you test the effect of removing the (string message) ctor, and see if that at least forces Castle to use the ctor with the Repostiory ?
Otherwise we call AddComponent(name, type, type). Other than that it really should work...
Also does this hint at my first idea ? How do I use Windsor to inject dependencies into ActionFilterAttributes