Translate property name in error messages with FluentValidation - asp.net-core

I use FluentValidation in my project in order to validate almost every requests coming into my WebApi.
It works fine, but I've been asked to translate property names in the error messages. My projet must handle at least french and english, so for example, what I want to achieve is :
'First Name' is required (english case)
'Prénom' est requis (french case)
I already have a IPropertyLabelService for other purposes, that is injected in the Startup.cs, that I want to use. It finds translations of property names in a .json, which already works fine.
My problem is that I don't know how to use it globally. I know that FluentValidation's doc says to set the ValidatorOptions.DisplayNameResolver in the Startup file, like this :
FluentValidation.ValidatorOptions.DisplayNameResolver = (type, memberInfo, expression) => {
// Do something
};
I don't know how I can use my IPropertyLabelService inside this, as the Startup.ConfigureServices method is not over yet, so I can't resolve my service...
Any other solution to achieve this behaviour is also more than welcome. I considered using .WithMessage() or .WithName() but I have a really big amount of validators, that would be really long to add this to all individually.

I answered this over on the FluentValidation issue tracker, but for completeness will include the answer here too:
Ssetting FluentValidation.ValidatorOptions.Global.DisplayNameResolver is the correct way to handle this globally (or you can use WithName at the individual rule level).
You need to ensure that this is set once, globally. If you need the service provider to have been initialized first, then make sure you call it at a point after the service provider has been configured (but ensure you still only set it once).
The "options" configuration mechanism in .NET Core allows you to defer configuration until after the point services have been constructed, so you can create a class that implements IConfigureOptions, which will be instantiated and executed during the configuration phase for a particular options type. FluentValidation doesn't provide any options configuration itself, so you can just hook into one of the built-in options classes (ASP.NET's MvcOptions is probably the simplest, but you can also use a different one if you're not using mvc).
For example, you could do something like this inside your ConfigureServices method:
public void ConfigureServices(IServiceCollection services) {
// ... your normal configuration ...
services.AddMvc().AddFluentValidation();
// Afterwards define some deferred configuration:
services.AddSingleton<IConfigureOptions<MvcOptions>, DeferredConfiguration>();
}
// And here's the configuration class. You can inject any services you need in its constructor as with any other DI-enabled service. Make sure your IPropertyLabelService is registered as a singleton.
public class DeferredConfiguration : IConfigureOptions<MvcOptions> {
private IPropertyLabelService _labelService;
public DeferredConfiguration(IPropertyLabelService labelService) {
_labelService = labelService;
}
public void Configure(MvcOptions options) {
FluentValidation.ValidatorOptions.Global.DisplayNameResolver = (type, memberInfo, expression) => {
return _labelService.GetPropertyOrWhatever(memberInfo.Name);
};
}
}

Related

Adding DbContext for list of context types at runtime

To implement a plug-in system in a AspNet Core Mvc app, I would like a non-generic method to add a data context from a list of assemblies loaded dynamically at runtime, taking a Type parameter like this:
foreach(Type tp in pluginContexts)
{
services.AddDbContext(tp, options => ...);
}
instead of the usual
services.AddDbContext<PluginDataContext>(options => ...);
That's because for dynamically loaded assemblies, I can not provide the TContext type parameter to the AddDbContextPool method, since that's statically compiled and not available at compile time.
Background
This is for a larger Asp.Net Core MVC app. The plugins must be able to both access the main database of the overall app and a separate database of their own.
Plugin assemblies, containing domain code and their private database context are to be dropped in a specified directory.
The main app loads the plugin assembly dynamically upon startup.
The way I am solving this now is to have each controller get the IConfiguration instance injected, obtain the appropriate connection string from the config, and the database context is instantiated in the controller. Not so nice but does work.
One can easily inject a general class into the Services collection with AddScoped<>, and then use it as a sort of ServiceLocator - however, that is considered an antipattern.
I looked into the source code for AddDbContext but honestly I am lost.
Is there any simple way to achieve this?
Solved it by creating an extensibility point in the plugin assembly.
Define an interface in the main app, which all plugins must implement.
public interface IPluginContextRegistration
{
void RegisterContext(ref IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction);
String GetDatabaseName();
}
Create a class implementing this interface (in the plugin). It has access to the type of its private database context, thus can use the generic AddDbContext method:
public class DatabaseRegistration : IPluginContextRegistration
{
public void RegisterContext(ref IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction)
{
services.AddDbContext<Test1DbContext>(optionsAction);
}
public String GetDatabaseName()
{
return "test-plugin-db";
}
}
Then in the main app ASP.Net Startup.cs file, add following code, which calls the RegisterContext() method for each plugin. For example, if you want to use Sql Server:
void RegisterPluginDbContexts(ref IServiceCollection services, List<Assembly> assemblyList)
{
IEnumerable<IPluginContextRegistration> registrars = new List<IPluginContextRegistration>();
foreach (Assembly assembly in assemblyList)
{
registrars = registrars.Concat(GetClassInstances<IPluginContextRegistration>(assembly));
}
foreach (var reg in registrars)
{
String name = reg.GetDatabaseName();
String connStr = Configuration.GetConnectionString(name);
reg.RegisterContext(ref services, options => options.UseSqlServer(connStr));
}
}
For completeness - the method "GetClassInstances" is just a helper method using Reflection to obtain an instance of classes implementing the specified interface.
So it's simple after all - no need for re-writing framework code .

What is "DbContextOptions`1"?

I have Web API in ASP .NET Core. When I add a db context in Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<FixturesContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("FixturesDatabase")));
services.AddControllers();
}
I see the number of services in the "services" container raises by three, I think those are:
FixturesContext
DbContextOptions
DbContextOptions`1
I am curious what is "DbContextOptions1"? Does anyone know? I have tried googling it but not satysfying result. My goal is to replace original context with in-memory (to run integration tests without original database), so I'm deleting db context and its options and adding in-memory context instead of them.
The third service you are getting is a generic version of the DbContextOptions. When calling .ToString() on a generic type it often looks like this.
The reason why there are three instances is that EF adds a general DbContextOptions object and a more specific one for your defined context.
If you inspect the calls of the third service you should find the type of your DbContext as a generic parameter.
DbContextOptions'1 would be the generic DbContextOptions<FixturesContext> registered to be injected into the context when being initialized.
Reference Configuring DbContextOptions
public class FixturesContext : DbContext
{
public FixturesContext(DbContextOptions<FixturesContext> options)
: base(options)
{ }
//...
}

Inject httpcontext into custom attribute outside controller in .net core

I need to inject httpcontext into custom attribute that is used outside the controller. I found several solutions how to do it in controller, but my case is little tricky. Now I have following code in my PermissionController
[PermissionFilter(PermissionEnum.Permission, AccessLevelEnum.Create)] <-- it works perfectly
[HttpPost("users/{userId}")]
public async Task<IActionResult>
AssignPermissionToUser([FromBody] List<PermissionToVM> permissions, int userId)
{
await _permissionService.Assign(permissions); <-- .Assign() extension
//code goes here
}
In the method above there is a call of extension method .Assign. This method code is available below.
//[SecondPermissionFilter(PermissionEnum.Permission,
AccessLevelEnum.Create)] <-- here I check permissions but don't
know how to inject the httpcontext
public async Task Assign(List<PermissionToVM> permissions)
{
//code goes here
}
As mentioned in many websites I visited f.e. here https://dotnetcoretutorials.com/2017/01/05/accessing-httpcontext-asp-net-core/ injecting of httpcontext outside the controller can be done using IHttpContextAccessor. The problem is that I don't know how to use it without passing it into constructor. My custom attribute should be called as decorator [SecondPermissionFilter(PermissionEnum.Permission, AccessLevelEnum.Create)] when only permission settings should be passed, so there is no any reference to httpcontextaccessor.
Is this even possible? If not, there is maybe another way to do this?
EDIT: Here is the code of SecondPermissionFilter class:
public sealed class SecondPermissionFilterAttribute : Attribute
{
private readonly PermissionEnum _requestedPermission;
private readonly IEnumerable<AccessLevelEnum> _accessLevelCollection;
private readonly IHttpContextAccessor _contextAccessor; //<-- how to inject?
public PermissionFilterAttribute(PermissionEnum requestedPermission, params AccessLevelEnum[] accessLevelCollection)
{
_requestedPermission = requestedPermission;
_accessLevelCollection = accessLevelCollection;
}
}
What you are after is something called Property Injection. As per the official docs this is not something that is supported out of the box by the .NET Core DI Container.
You can however use a third party library such as Ninject or Autofac - both of which are available via NuGet.
In my opinion the Ninject syntax is nicer, however as noted in this answer, and this answer property injection itself is considered bad practice. So if possible I would try to avoid it.
So you should instead use one of the three methods specified by the filter documentation, this answer breaks things down a bit more.
Edit
This answer deals specificically with Attribute injection, the second answer looks to achieve this without external dependencies.

sharp architecture contrib transaction attribute in windows service

For some reason this:
[Transaction]
public void DoSomething()
{
...
}
does not work I still have to explicitly use the transaction like this:
public void DoSomething()
{
using (var tx = NHibernateSession.Current.BeginTransaction())
{
....
tx.Commit();
}
}
Any ideas why?
I am using something like this to bootstrap stuff:
_container = new WindsorContainer();
ComponentRegistrar.AddComponentsTo(_container);
...
ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(_container));
ComponentRegistrar.AddComponentsTo(_container, typeof(NHibernateTransactionManager));
NHibernateSession.Init(new ThreadSessionStorage(),
new[] { "Bla.Domain.dll" },
new AutoPersistenceModelGenerator().Generate(),
"NHibernate.config");
As Doan said the component that had the method is not proxied.
Since the method is not virtual, I am assuming that your class is implementing an interface. make sure that you have the dependency in the class calling DoSomething defined as the interface and not the implementing class.
if you debug the code, and check the run time type of the object, it should be a castle proxy
for more details check the trouble shooting section on Sharp Architecture contrib wiki
https://github.com/sharparchitecture/Sharp-Architecture-Contrib/wiki/Troubleshooting
Normally, this kind of problem is caused by the failure of invoking the dynamic proxy that provides the transaction management service. Two of the most common errors are:
The method cannot be proxied: most likely not implement any interface method, or the object was not proxied.
The method was called from the same class, which bypassed all proxies.
Edit:
I guess you use Castle Windsor as IoC container. The [Transaction] decoration requires the Automatic Transaction Management Facility in order to work. If you successfully configured the facility, i.e. you made [Transaction] work in one method, but not other, then the answer above applies. If all Transaction decoration failed to work, then you have to review the configuration of the facility first.

Autofac - Lifetime and modules

Problem (abstract)
Given a module which registers dependency X. The dependency X has a different lifetime in a MVC3 app (lifetime per HttpRequest) then in a console application (dependency per lifetimescope with a name). Where or how to specify the lifetime of dependency X?
Case
I've put all my database related code in a assembly with a module in it which registers all repositories. Now the ISession (Nhibernate) registration is also in the module.
ISession is dependency X (in the given problem case). ISession has different lifetime in a MVC3 app (lifetime per request) then in a console app where I define a named lifetimescope.
Should the registration of ISession be outside the module? Would be strange since it's an implementation detail.
What is the best case to do here? Design flaw or are there smart constructions for this :) ?
Given your use case description, I'd say you have a few of options.
First, you could just have each application register their own set of dependencies including lifetime scope. Having one or two "duplicate" pieces of code in this respect isn't that big of a deal considering the differences between the application and the fact that the registrations appear fairly small.
Second, you could wrap the common part (minus lifetime scope) into a ContainerBuilder extension method that could be used in each application. It would still mean each app has a little "duplicate code" but the common logic would be wrapped in a simple extension.
public static IRegistrationBuilder<TLimit, ScanningActivatorData, DynamicRegistrationStyle>
RegisterConnection<TLimit, ScanningActivatorData, DynamicRegistrationStyle>(this ContainerBuilder builder)
{
// Put the common logic here:
builder.Register(...).AsImplementedInterfaces();
}
Consuming such an extension in each app would look like:
builder.RegisterConnection().InstancePerHttpRequest();
// or
builder.RegisterConnection().InstancePerLifetimeScope();
Finally, if you know it's either web or non-web, you could make a custom module that handles the switch:
public class ConnectionModule : Autofac.Module
{
bool _isWeb;
public ConnectionModule(bool isWeb)
{
this._isWeb = isWeb;
}
protected override void Load(ContainerBuilder builder)
{
var reg = builder.Register(...).AsImplementedInterfaces();
if(this._isWeb)
{
reg.InstancePerHttpRequest();
}
else
{
reg.InstancePerLifetimeScope();
}
}
}
In each application, you could then register the module:
// Web application:
builder.RegisterModule(new ConnectionModule(true));
// Non-web application:
builder.RegisterModule(new ConnectionModule(false));
Alternatively, you mentioned your lifetime scope in your other apps has a name. You could make your module take the name:
public class ConnectionModule : Autofac.Module
{
object _scopeTag;
public ConnectionModule(object scopeTag)
{
this._scopeTag = scopeTag;
}
protected override void Load(ContainerBuilder builder)
{
var reg = builder.Register(...)
.AsImplementedInterfaces()
.InstancePerMatchingLifetimeScope(this._scopeTag);
}
}
Consumption is similar:
// Web application (using the standard tag normally provided):
builder.RegisterModule(new ConnectionModule("httpRequest"));
// Non-web application (using your custom scope name):
builder.RegisterModule(new ConnectionModule("yourOtherScopeName"));
I would recommend against simply using InstancePerLifetimeScope in a web application unless that's actually what you intend. As noted in other answers/comments, InstancePerHttpRequest uses a specific named lifetime scope so that it's safe to create child lifetime scopes; using InstancePerLifetimeScope doesn't have such a restriction so you'll actually get one connection per child scope rather than one connection for the request. I, personally, don't assume that other developers won't make use of child lifetime scopes (which is a recommended practice), so in my applications I'm very specific. If you're in total control of your application and you can assure that you aren't creating additional child scopes or that you actually do want one connection per scope, then maybe InstancePerLifetimeScope will solve your problem.
It's common practice to use a one connection per http request. That being the case, connections would be registered using .InstansePerLifetimeScope(). For example, you might do something like:
builder
.Register(c => {
var conn = new SqlConnection(GetConnectionString());
conn.Open();
return conn;
})
.AsImplementedInterfaces()
.InstancePerLifetimeScope();