I'm trying to use FluentValidation in a WebApi project (not asp.net Core).
I have the following code:
public static class UnityConfig
{
public static void RegisterComponents(UnityContainer container)
{
// Register validators
RegisterValidators(container);
// Mediatr
container.RegisterType<IMediator, Mediator>();
container.RegisterTypes(AllClasses.FromAssemblies(true, Assembly.GetExecutingAssembly()), WithMappings.FromAllInterfaces, GetName, GetLifetimeManager);
container.RegisterInstance<SingleInstanceFactory>(t => container.Resolve(t));
container.RegisterInstance<MultiInstanceFactory>(t => container.ResolveAll(t));
// Automapper profiles
var profileTypes = typeof(BaseProfile).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(BaseProfile)));
var config = new MapperConfiguration(cfg => new MapperConfiguration(x =>
{
foreach (var type in profileTypes)
{
var profile = (BaseProfile)Activator.CreateInstance(type);
cfg.AddProfile(profile);
}
}));
container.RegisterInstance<IConfigurationProvider>(config);
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
static LifetimeManager GetLifetimeManager(Type type)
{
return IsNotificationHandler(type) ? new ContainerControlledLifetimeManager() : null;
}
static string GetName(Type type)
{
return IsNotificationHandler(type) ? string.Format("HandlerFor" + type.Name) : string.Empty;
}
private static void RegisterValidators(IUnityContainer container)
{
var validators = AssemblyScanner.FindValidatorsInAssembly(Assembly.GetExecutingAssembly());
validators.ForEach(validator => container.RegisterType(validator.InterfaceType, validator.ValidatorType));
}
}
I'm scanning the assemblies and registrering the validators, of which there's only one right now, it sits here: (don't mind the weird validations, I'm trying to have it fail)
public class Query : IRequest<Result>
{
public Guid? Id { get; set; }
}
public class QueryValidator : AbstractValidator<Query>
{
public QueryValidator()
{
RuleFor(q => q.Id).Empty();
RuleFor(q => q.Id).Equal(Guid.NewGuid());
}
}
My Application_start looks like this:
protected void Application_Start()
{
var container = new UnityContainer();
UnityConfig.RegisterComponents(container);
GlobalConfiguration.Configure(WebApiConfig.Register);
var factory = new UnityValidatorFactory2(GlobalConfiguration.Configuration);
FluentValidationModelValidatorProvider.Configure(GlobalConfiguration.Configuration, x => x.ValidatorFactory = factory);
}
And I have the following validatorFactory:
public class UnityValidatorFactory2 : ValidatorFactoryBase
{
private readonly HttpConfiguration _configuration;
public UnityValidatorFactory2(HttpConfiguration configuration)
{
_configuration = configuration;
}
public override IValidator CreateInstance(Type validatorType)
{
var validator = _configuration.DependencyResolver.GetService(validatorType) as IValidator;
return validator;
}
}
Now; when I call the action on the controller, 'CreateInstance' tries to resolve a validatorType of the type:
IValidator<Guid>
instead of:
IValidator<Query>
and of course finds nothing, this means that my validations does not run.
Does anyone have an ideas as to why this is? it seems faily straight forward, so I have trouble seeing what goes wrong.
After having slept on it, I found the answer myself.
I was posting a Guid to my controller instead of the model I was trying to validate (which only contains a guid)
After posting the right model, it now validates correctly.
Related
I'm using the Mediatr library to register and call my RequestHandlers.
Everything went fine until I started reading more about integrated tests.
PLEASE READ AFTER EDIT
I can't call my class which inherits from the RequesHandler.
My class looks like this:
public class MyRequestHandler : RequestHandler<MyRequest, MyResponse>
{
....
}
I'm not using the Meditr async and I'm using .net framework 4.7 instead of asp.net core, so, everything looks like returns me answers for asp.net core.
When I construct MyTestClass, to construct the RequestHandler I have to create a ServiceFactory and maybe this is the problem because I don't know how.
public MyClassTest()
{
ServiceFactory sv = null;
_mediator = new Mediator(sv);
}
EDIT
Providing more info
I have this Handler in my Application Layer
public class LogInUserByFormHandler : RequestHandler<LogInUserByFormRequest, LogInUserByFormResponse>
{
private readonly IValidator<LogInUserByFormRequest> _validator;
public LogInUserByFormHandler(IValidator<LogInUserByFormRequest> validator)
{
_validator = validator;
}
protected override LogInUserByFormResponse Handle(LogInUserByFormRequest request)
{
_validator.ValidateAndThrow(request);
var userInfo = GetUserInfo(request);
ValidateLogInUserByFormRules(userInfo);
var userLoginInfo = GetValidUserLoginInfo(request);
ValidateUserLoginInfoByFormRules(userLoginInfo);
var sessionKey = CreateUserSessionKey(userInfo);
var response = new LogInUserByFormResponse
{
UserName = request.UserName,
SessionKey = sessionKey,
UserId = userInfo.id_usuario
};
return response;
}
//A LOT OF CODE HERE, methods and etc
}
As it's possible to see, it implements the Mediatr.
On my Web Project on Presentation Layer, I used AutoFac to Inject the Handlers, so, any Request I do is always handled by the right method.
All I have to do is call, like this:
var logInByFormRequest = new LogInUserByFormRequest
{
UserName = viewModel.UserName,
Password = viewModel.Password
};
var response = _mediator.Send(logInByFormRequest).Result;
This works like a charm. The problem now is on the Test project. It references the Application as the Presentation Project does.
I don't know how to make the mediator.send find the right method.
EDIT²
Here comes my test code
[TestClass]
public class LogInUserByFormTest
{
private LogInUserByFormRequest CreateRequest(string userName, string password)
{
LogInUserByFormRequest request = new LogInUserByFormRequest
{
UserName = userName,
Password = password
};
return request;
}
[TestMethod]
[Description("")]
public void UserName_ShouldHave_Max_30Characters_Exception()
{
try
{
var request = CreateRequest("UserNameIsGreaterThanAllowed", "password");
var mediator = new Mock<IMediator>();
var response = mediator.Object.Send(request).Result;
}
catch (System.Exception ex)
{
throw;
}
}
}
The result (response) is always null and the mediator doesn't call the right handler.
EDIT3
Here is how I register the handlers and validators.
I use autofac. This class here is called on the global.asax
public class AutofacConfig
{
public static void ConfigureContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
builder.RegisterType<Mediator>().As<IMediator>().InstancePerLifetimeScope();
builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();
builder.RegisterType<FluentValidationModelValidatorProvider>().As<ModelValidatorProvider>();
builder.RegisterType<RegistryManagerService>().As<IRegistryManagerService>().SingleInstance().WithParameter("appName", ConfigurationManager.AppSettings["APPNAME"]);
builder.Register<ServiceFactory>(context =>
{
var c = context.Resolve<IComponentContext>();
return t => c.Resolve(t);
});
builder.RegisterAssemblyTypes(Assembly.Load("Docspider.Application"))
.Where(x => x.Name.EndsWith("Handler"))
.AsImplementedInterfaces();
builder.RegisterAssemblyTypes(Assembly.Load("Docspider.Application"))
.Where(x => x.Name.EndsWith("Validator"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
public class AutofacValidatorFactory : ValidatorFactoryBase
{
private readonly IComponentContext _context;
public AutofacValidatorFactory(IComponentContext context)
{
_context = context;
}
public override IValidator CreateInstance(Type validatorType)
{
if (_context.TryResolve(validatorType, out object instance))
{
var validator = instance as IValidator;
return validator;
}
return null;
}
}
For such an integration test you would need to configure the necessary dependencies. Since you have indicated that Autofac is being used then configure a container just as you would have in production. Use the container to get the mediator and perform the desired test.
For example.
[TestClass]
public class LogInUserByForm_IntegrartionTest {
private LogInUserByFormRequest CreateRequest(string userName, string password) {
LogInUserByFormRequest request = new LogInUserByFormRequest {
UserName = userName,
Password = password
};
return request;
}
IMediator BuildMediator() {
//AutoFac
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
var mediatrOpenTypes = new[] {
typeof(IRequestHandler<,>)
};
foreach (var mediatrOpenType in mediatrOpenTypes) {
builder
.RegisterAssemblyTypes(typeof(LogInUserByFormRequest).GetTypeInfo().Assembly)
.AsClosedTypesOf(mediatrOpenType)
.AsImplementedInterfaces();
}
builder.Register<ServiceFactory>(ctx => {
var c = ctx.Resolve<IComponentContext>();
return t => c.Resolve(t);
});
//...all other needed dependencies.
//...
var container = builder.Build();
var mediator = container.Resolve<IMediator>();
return mediator;
}
[TestMethod]
[Description("")]
public async Task UserName_ShouldHave_Max_30Characters_Exception() {
try
{
//Arrange
var request = CreateRequest("UserNameIsGreaterThanAllowed", "password");
var mediator = BuildMediator();
//Act
var response = await mediator.Send(request);
//Assert
//...assert the expected values of response.
}
catch (System.Exception ex)
{
throw;
}
}
}
The above was modeled after the examples provided by MediatR.Examples.Autofac
I have made a claims filter
public class ClaimRequirementAttribute : TypeFilterAttribute
{
public ClaimRequirementAttribute(string claimType, ClaimRoles claimValue) : base(typeof(ClaimRequirementFilter))
{
Arguments = new object[] {new Claim(claimType, claimValue.ToString()) };
}
}
public class ClaimRequirementFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var headers = context.HttpContext.Request.Headers;
var tokenSuccess = headers.TryGetValue("Token", out var token);
var emailSuccess = headers.TryGetValue("Email", out var email);
var deviceNameSuccess = headers.TryGetValue("DeviceName", out var deviceName);
if (tokenSuccess && emailSuccess && deviceNameSuccess)
{
var accountLogic = context.HttpContext.RequestServices.GetService<IAccountLogic>();
var hasClaim = accountLogic.ValidateLogin(email, token, deviceName).Result.Success;
if (!hasClaim)
{
context.HttpContext.ForbidAsync();
}
}
else
{
context.HttpContext.ForbidAsync();
}
}
}
I have registered the filter in my startup
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ConnectionStringsSettings>(Configuration.GetSection("ConnectionStrings"));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddScoped<ClaimRequirementFilter>();
But I get this error when I navigate to an action that uses the filter
[HttpPost]
[ClaimRequirement("Permission", ClaimRoles.Admin)]
public async Task ResetLeaderboard()
InvalidOperationException: A suitable constructor for type 'Foosball.Logic.ClaimRequirementFilter' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor
github: https://github.com/Mech0z/Foosball/tree/core2.1/Foosball
As your code has
Arguments = new object[] {new Claim(claimType, claimValue.ToString()) };
you need to add the following constructor:
public ClaimRequirementFilter(Claim claim)
{
}
That is because the internal constructor resolving logic uses TypeFilterAttribute.Argument property to decide what constructor to use for instantiation.
I'm trying to set up a signalr hub on my project, using simpleinjector for dependency injection.
I have some configuration in Startup.cs
[assembly: OwinStartup(typeof(Startup))]
namespace CallCentre.Client
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = new Container();
container.Register<TwilioHub>();
container.Verify();
var config = new HubConfiguration()
{
Resolver = new SignalRSimpleInjectorDependencyResolver(container)
};
app.MapSignalR(config);
}
}
}
DI Resolver
public class SignalRSimpleInjectorDependencyResolver : DefaultDependencyResolver
{
private readonly Container _container;
public SignalRSimpleInjectorDependencyResolver(Container container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
return ((IServiceProvider)_container).GetService(serviceType)
?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType)
.Concat(base.GetServices(serviceType));
}
}
My hub
public class TwilioHub : Hub
{
public void Send(int callCount, int queueId)
{
var context = GlobalHost.ConnectionManager.GetHubContext<TwilioHub>();
context.Clients.All.updateQueueCount(callCount, queueId);
}
}
A class elsewhere in the solution where the hub is called
public class QueueStateHandler : IQueueStateHandler
{
private readonly TwilioHub _twilioHub;
public QueueStateHandler(TwilioHub twilioHub)
{
_twilioHub = twilioHub;
}
public void IncrementQueueById(int id)
{
_twilioHub.Send(5,1);
}
}
And my frontend code
$(function () {
var hub = $.connection.twilioHub;
hub.logging = true;
var queue = $('#QueueCount');
hub.client.updateQueueCount = function(queueCount, id) {
alert(queueCount);
};
$.connection.hub.start();
});
I can set everything up using straight web api, skipping the DI and everything works fine. As soon as I bring in DI I start running into problems. At the moment its silently falling over somewhere. I can step through the code and end up in the hub, but nothing happens in my frontend.
Any pointers as to what I'm doing wrong would be greatly appreciated.
I am trying to get Automapper to play nice with Autofac in an ASP.Net MVC application.
I have followed the instructions in the answer to this: Autofac 3 and Automapper
However it fails on the first call to _mapper.Map<>(...)
Autofac is setup like this:
builder.RegisterType<EntityMappingProfile>().As<Profile>();
builder.Register(ctx => new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers))
.AsImplementedInterfaces()
.SingleInstance()
.OnActivating(x =>
{
foreach (var profile in x.Context.Resolve<IEnumerable<Profile>>())
{
x.Instance.AddProfile(profile);
}
});
builder.RegisterType<MappingEngine>().As<IMappingEngine>();
and then in my business layer I have a service like this:
public class LinkService : ILinkService
{
private readonly ILinkRepository _linkRepository;
private readonly IMappingEngine _mapper;
public LinkService(ILinkRepository linkRepository, IMappingEngine mapper)
{
_linkRepository = linkRepository;
_mapper = mapper;
}
public IEnumerable<LinkEntity> Get()
{
var links = _linkRepository.Get().ToList();
return _mapper.Map<IEnumerable<Link>, IEnumerable<LinkEntity>>(links);
}
public LinkEntity GetById(int id)
{
var link = _linkRepository.GetById(id);
return _mapper.Map<Link, LinkEntity>(link);
}
}
The call to _mapper.Map<IEnumerable<Link>, IEnumerable<LinkEntity>>
fails with:
Missing type map configuration or unsupported mapping.
Any ideas where I might be going wrong?
you're missing creating Mapper, create map Link to LinkEntity in EntityMappingProfile:
internal class EntityMappingProfile :Profile
{
protected override void Configure()
{
base.Configure();
this.CreateMap<Link, LinkEntity>();
}
}
I have two implementations of an interface that in plain old c# would be instantiated like so:
var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
var oven = useCache
? new CachedCookieOven(new CookieOven())
: new CookieOven();
var controller = new CookieController(oven); // MVC Controller
here is the interface and classes:
public interface ICookieOven {
IEnumerable<Cookie> Bake();
}
public class CookieOven : ICookieOven {
public IEnumerable<Cookie> Bake() {
var list = new List<Cookie>();
// bake cookies and return them
return list;
}
}
public class CachedCookieOven : ICookieOven {
readonly ICookieOven _oven;
public CachedCookieOven(ICookieOven oven) { _oven = oven; }
public IEnumerable<Cookie> Bake() {
var cookies = GetFromPlate();
return cookies ?? _oven.Bake();
}
}
My MVC controller has the following constructor
public class CookieController : Controller {
readonly ICookieOven _oven;
public CookieController(ICookieOven oven) { _oven = oven; }
public ActionResult ViewCookies() {
var bakedCookies = _oven.Bake();
return View(bakedCookies);
}
}
The Bootstrapper class that is created says in the comments that I don't need to register my mvc controller classes
public static class Bootstrapper
{
public static IUnityContainer Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
RegisterTypes(container);
return container;
}
public static void RegisterTypes(IUnityContainer container)
{
}
}
In Unity I have registered both instances. There may be a better way and if so tell me.
public static class Bootstrapper {
// ...
private static IUnityContainer BuildUnityContainer() {
var container = new UnityContainer();
var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
// register
container.RegisterType<ICookieOven, CookieOven>("oven");
if (useCache) {
container.RegisterType<ICookieOven, CachedCookieOven>("cachedOven",
new InjectionConstructor(container.Resolve<ICookieOven>("oven"));
}
}
}
How do I ensure that the correct instance of ICookieOven gets sent to the constructor of the CookieController mvc controller?
Registering types in Unity without a name makes that the default type. If you want to register more than one type, you have to provide a name. The following is the correct way to register my types in the Bootstrapper class:
public static void RegisterTypes(IUnityContainer container)
{
var useCache = bool.Parse(ConfigurationManager.AppSettings["useCache"]);
if (useCache) {
// named, this is not the default
container.RegisterType<ICookieOven,CookieOven>("oven");
// this one is not named and is the default
container.RegisterType<ICookieOven,CachedCookieOven>(new InjectionConstructor(
container.Resolve<ICookieOven>("oven"));
} else {
// notice it is not named, it is the default
container.RegisterType<ICookieOven,CookieOven>();
}
}
You want to create an object but which one depends on a value only known at runtime. What you need is a factory (couple of examples here).
To implement this, one approach could be like this: your controller could depend on a IOvenFactory, injected in controller's constructor. When you need the oven you can call _ovenFactory.Create().
In an IOvenFactory implementation, you could have the logic of how to create, depending on the configuration value.