Inject into asp.net web api model with autofac - c#

I want to use IValidatableObject.Validate() to check some aspects of my model against a repository before processing requests. However, with the config below _dalForValidation is never set in on Models.App, in other words the default empty constructor is always being called.
private static void ConfigureAutofac()
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<DataAccessFacade>().As<IDataAccess>().InstancePerApiRequest();
builder.RegisterType<Models.App>();
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
App has 2 constructors:
public App(IDataAccess dalForValidation)
{
_dalForValidation = dalForValidation;
}
public App() {}
for completeness this is where I try to access it, getting a null reference exception:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var existingApps = _dalForValidation.FindApps().Convert<DB.App,App>();
if (!ValidateProxyMappings(existingApps))
yield return new ValidationResult("Invalid proxy mapping");
}
Perhaps the dependency resolver is not used for the model, or is there something else I'm missing here?

Related

FluentValidation with Owin ignores [FromUri] Dtos in Asp.Net WebApi2

I'm developing an ASP.NET WebApi2 (.NET 4.7.2) with Owin and Autofac as IOC container. The Dtos shall get validated with FluentValidation before reaching the controller. Here is my project configuration:
public class Startup
{
public void Configuration(IAppBuilder app)
{
...
var config = new HttpConfiguration();
config.Filters.Add(new ValidateDtoStateFilter());
...
FluentValidationModelValidatorProvider.Configure(config);
...
}
}
Validate dto state filter:
public class ValidateDtoStateFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
throw new ValidationException(actionContext.ModelState
.SelectMany(ms => ms.Value.Errors
.Select(er => new ValidationFailure(ms.Key.Split('.')[1].FromPascalToCamelCase(), er.ErrorMessage))));
}
}
}
Autofac builder configuration:
builder.RegisterAssemblyTypes(typeof(MyDtoValidator).Assembly)
.Where(t => t.Name.EndsWith("Validator"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterType<FluentValidationModelValidatorProvider>().As<ModelValidatorProvider>();
builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();
Autofac validator factory:
public class AutofacValidatorFactory : ValidatorFactoryBase
{
private readonly IComponentContext _context;
public AutofacValidatorFactory(IComponentContext context)
{
_context = context;
}
public override IValidator CreateInstance(Type validatorType)
{
object instance;
return _context.TryResolve(validatorType, out instance) ? instance as IValidator : null;
}
}
It works fine with POST or PUT endpoints where the dto comes [FromBody] in the requets payload. It does not work with [FromUri] dtos, e.g. in a GET request. The validator will be created by Autofac, but in OnActionExecuting of ValidateDtoStateFilter actionContext.ModelState is always true, no matter if the supplied data is valid or not.
How can I achieve that [FromUri] dtos get validated by the FluentValidation middleware as well?
Update
The issue does not occur any more without my having changed anything.
I could not reproduce this behaviour. Tested with Autofac 6.0.0 and FluentValidation 8.6.1. However, both [FromUri] and [FromBody] dtos set actionContext.ModelState.IsValid to true when the model is null (either no query string parameters passed or request body is empty). In this case no errors are generated so the validation passes.
This is actually by design. The purpose of FluentValidation is to validate properties on objects, which by definition requires a non-null instance in order to work.
https://github.com/FluentValidation/FluentValidation/issues/486
I can think of two ways to work around this limitation.
In your controller, simply test the dto is null:
[HttpGet]
public IHttpActionResult Get([FromUri] MyDto dto)
{
if (dto == null) return BadRequest();
...
}
Update the ValidateDtoStateFilter class to manually trigger validation of null dtos that have validator defined:
public class ValidateDtoStateFilter : ActionFilterAttribute
{
private readonly IDependencyResolver _resolver;
public ValidateDtoStateFilter(IDependencyResolver resolver)
{
_resolver = resolver;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var parameters = actionContext.ActionDescriptor.GetParameters();
var nullDtosWithValidatorDefined = actionContext.ActionArguments
.Where(argument => argument.Value == null)
.Select(argument => new
{
argument.Key,
// you may need to account for p.IsOptional and p.DefaultValue here
Type = parameters.FirstOrDefault(p => p.ParameterName == argument.Key)?.ParameterType
})
.Where(argument => argument.Type != null)
.Select(argument => new {
argument.Key,
Validator = (IValidator)_resolver.GetService(typeof(IValidator<>).MakeGenericType(argument.Type))
})
.Where(argument => argument.Validator != null)
.Select(argument => argument.Key);
foreach (var dto in nullDtosWithValidatorDefined)
{
actionContext.ModelState.AddModelError(dto, $"'{dto}' must not be null.");
}
if (!actionContext.ModelState.IsValid)
{
var errors = actionContext
.ModelState
.SelectMany(ms => ms.Value.Errors
.Select(er => new ValidationFailure(ms.Key, er.ErrorMessage))
);
throw new ValidationException(errors);
}
}
}
// in the Startup.cs file the ValidateDtoStateFilter must be added after the DependencyResolver is set to Autofac:
config.DependencyResolver = new AutofacWebApiDependencyResolver(ConfigureAutofac());
config.Filters.Add(new ValidateDtoStateFilter(config.DependencyResolver));
This may not answer your specific problem though, it would be easier if you shared a link to your project or a snippet of your Startup.cs file, as it could be something with your api configuration.

Service Stack inject object

i´m doing an app, using ServiceStack. I could inject an object without problems, but, the object can be modified outside the Service Class, so, i need to re inject again
Here is the code:
public class ClientManager: ApplicationContext{
public ClientManager(AppConfig appConfig)
{
_appConfig = appConfig;
_activeForm = LayoutFactory(appConfig.Layout);
var appHost = new AppHost(_activeForm, _appConfig);
var listeningOn = string.Format("http://*:{0}/", new Uri(appConfig.UrlBroker).Port);
appHost.Init();
appHost.Start(listeningOn);
var timerMetadata = new Timer(CheckMetadata, null, 0, 60000);
}
}
public class AppHost : AppSelfHostBase
{
private ILayout _layout;
private AppConfig _appConfig;
public AppHost(ILayout activeForm, AppConfig appConfig)
: base("ClientService", typeof(ClientService).Assembly)
{
_layout = activeForm;
_appConfig = appConfig;
}
public override void Configure(Container container)
{
container.Register("activeForm", _layout);
container.Register("config", _appConfig);
}
}
public class ClientService : Service
{
public HttpResult Post(Person request)
{
HttpResult response = new HttpResult();
_initConf = ServiceStackHost.Instance.Container.ResolveNamed<AppConfig>("config");
}
}
So, the class ClientManager has a thread which can modify the object appConfig and activeForm (this objects are injected into the service class)
Now, if i modify the object, it doesn´t inject it again. I think thath i should dispose the AppHost, and start it again, what do you think?
Thanks
It's very rare that you'd want to dispose the AppHost unless you're running Integration tests where you want to start/destroy multiple AppHost instances.
Also I'd strongly recommend against using names when registering dependencies, just use the types of the dependencies as normal, e.g:
container.Register(_layout);
container.Register(_appConfig);
Any dependencies registered in the IOC are then automatically injected into your Service class by declaring a public property with that type, e.g:
public class ClientService : Service
{
public AppConfig AppConfig { get; set; }
public HttpResult Post(Person request)
{
HttpResult response = new HttpResult();
var _initConf = AppConfig;
}
}
This injects the same instance that's registered in the IOC, so if you modify the instance later the Service would inject the same modified instance by default.

How do I gain access to a repository in a custom ValidationAttribute?

public class UniqueNameAttribute : ValidationAttribute
{
private const string UniqueNameViolationMessage = "This name is already taken. Please select another.";
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//return somerepo.IsUniqueName(name)
//how do I get access to repo here? Tried DI with autofac but it came out as null
}
}
I'm using dependency injection to inject repositories into my Web API. However, it seems I cannot inject into a ValidationAttribute. It comes out as null if I try to inject. I'm using Autofac for DI. Is there another way I can gain access to my repo?
Note that I am only using Web API, not MVC, so I cannot use the MVC DependencyResolver.
builder.RegisterType<MyRepository>().As<IMyRepository>().InstancePerRequest();
var container = builder.Build();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver((IContainer)container); ;
I'm guessing you're missing this line:
var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
And rather than inherit from IActionFilter, inherit from IAutofacActionFilter.
More details here: https://autofaccn.readthedocs.io/en/latest/integration/webapi.html#provide-filters-via-dependency-injection

Child container registration based on route parameters

We have a multi-tennant ASP.NET MVC application that hosts a booking engine for multiple clients. Each of these clients has multiple packages that can influence Unity Container configuration. We are creating a child container per request and registering different interface implementations based on the client and package parameters passed through the route.
Currently we are accomplishing this by doing the following:
Controller has a property ServiceLocator that uses a unity container to resolve dependencies.
Controller gets IUnityContainer injected and assigned to a property.
Controller has a custom ActionFilterAttribute that accesses the controllers unity container, creates a child container, conditionally registers dependency implementations based on client and package route parameters, then assigns this child container to the controller's serviceLocator.
Controller uses serviceLocator on demand to resolve individual dependencies.
This works but is really clumsy and I feel eventually it will be unsustainable. I'm looking for a better solution.
We're stuck on .NET 4.0 at the moment until we wrap up some legacy stuff so I'm targeting Unity 2 specifically.
I've tried creating a custom IDependencyResolver to create the child container and register dependencies based on route parameters storing the container in either Session or in HttpContext items but ran into the null HttpContext problems. Is there any other way to base registrations on the route and have the dependencies injected to the controller constructor?
Eventually I will need a solution for Web API as well.
Edit: Example
public interface IRateService { ... }
public class RemoteRateService : IRateService { ... }
public class LocalRateService : IRateService { ... }
public class CustomDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
if(ChildContainer == null)
{
ChildContainer = _container.CreateChildContainer();
var routeData = HttpContext.Current.Request.RequestContext.RouteData.Values;
if(routeData["client"] == "ClientA")
ChildContainer.RegisterType<IRateService, RemoteRateService>();
else
ChildContainer.RegisterType<IRateService, LocalRateService>();
}
return ChildContainer.Resolve(serviceType);
}
}
public class RateController : Controller
{
private IRateService _rateService;
public RateController(IRateService rateService)
{
_rateService = rateService;
}
...
}
url: /ClientA/Package1/Rate - RateController gets RemoteRateService
url: /ClientB/Package2/Rate - RateController gets LocalRateService
Abatishchev answered my question in the comments by pointing me in the right direction with IControllerFactory. For the random google searches that end here, here is the basic setup I used by inheriting from DefaultControllerFactory:
public class UnitySessionControllerFactory : DefaultControllerFactory
{
private const string HttpContextKey = "Container";
private readonly IUnityContainer _container;
public UnitySessionControllerFactory (IUnityContainer container)
{
_container = container;
}
protected IUnityContainer GetChildContainer(RequestContext requestContext)
{
var routeData = requestContext.RouteData.Values
?? new RouteValueDictionary();
var clientName = routeData["clientName"] as string;
var packageId = routeData["packageID"] as int?;
if (clientName == null)
throw new ArgumentException("ClientName not included in route parameters");
var childContainer = requestContext.HttpContext.Session[clientName + HttpContextKey] as IUnityContainer;
if (childContainer != null)
return childContainer;
requestContext.HttpContext.Session[clientName + HttpContextKey] = childContainer = _container.CreateChildContainer();
var moduleLoader = childContainer.Resolve<ModuleLoader>();
moduleLoader.LoadModules(clientName, packageId);
return childContainer;
}
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controllerType = GetControllerType(requestContext, controllerName);
var container = GetChildContainer(requestContext);
return container.Resolve(controllerType) as IController;
}
public override void ReleaseController(IController controller)
{
_container.Teardown(controller);
}
}
Forgive the use of session here. In the future I will exchange it for HttpContext.Items once I am able to wrangle in our project's use of session.
To enable the custom controller factory I added this line to the Bootstrapper.Initialise() method
ControllerBuilder.Current
.SetControllerFactory(new UnitySessionControllerFactory(container));

MVC Integration tests with Unity IoC

Am trying Unity IoC, after using constructor based DI.
Problem is trying to get integration tests working.
http://patrick.lioi.net/2013/06/20/streamlined-integration-tests/
"Running your integration tests should exercise as much of the real system as is reasonably possible"
Patrick above describes setting up an IoC inside the MVC Unit test project.. but I'm stuck as to how to implement
public class HomeController : Controller
{
readonly IWinterDb db;
// Unity knows that if IWinterDb interface is asked for, it will inject in a new WinterDb()
public HomeController(IWinterDb db)
{
this.db = db;
}
public ActionResult Index()
{
var stories = db.Query<Story>()
.OrderByDescending(s => s.Rating)
.Include(s => s.StoryType);
return View(stories);
}
Unit tests are fine, passing in a fake:
[TestMethod]
public void Index_GivenFake_ShouldReturn100Stories()
{
var db = new FakeWinterDb();
db.AddSet(TestData.Stories);
var controller = new HomeController(db);
var result = controller.Index() as ViewResult;
var model = result.Model as IEnumerable<Story>;
Assert.AreEqual(100, model.Count());
}
However I like integration tests which test the whole stack:
//Integration tests depend on the test data inserted in migrations
[TestClass]
public class HomeControllerTestsIntegration
{
[TestMethod]
public void Index_GivenNothing_ResultShouldNotBeNull()
{
var controller = new HomeController();
var result = controller.Index() as ViewResult;
Assert.IsNotNull(result);
}
Problem: This will not compile (as no parameterless constructor). And Unity is not being called to inject in the correct dependency for HomeController.
Unity wire up:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
container.RegisterType<IWinterDb, WinterDb>();
// for authentication
container.RegisterType<AccountController>(new InjectionConstructor());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
Edit1:
[TestMethod]
public void Index_GivenNothing_ResultShouldNotBeNull()
{
UnityConfig.RegisterComponents();
var controller = UnityConfig.container.Resolve<HomeController>();
var result = controller.Index() as ViewResult;
Assert.IsNotNull(result);
}
Making sure the singleton is there.
public static class UnityConfig
{
public static UnityContainer container;
public static void RegisterComponents()
{
container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
//container.RegisterType<IWinterDb, WinterDb>();
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromMatchingInterface, // Convention of an I in front of interface name
WithName.Default
); // Default not a singleton in Unity
// for authentication
container.RegisterType<AccountController>(new InjectionConstructor());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
Exposing Unity to the test project
You need to resolve your controller via the container for Unity to resolve dependencies for you.
It may be as simple as replacing this:
var controller = new HomeController();
with this:
var controller = container.Resolve<HomeController>();
You will obviously need to expose your container to your test class. This is something you would not normally do when wiring up your production code.

Categories