.Net Core Data Annotations - localization with shared resources - .net-core

I would like to use shared resx file to specify all the translatable strings (both for translator convenience, and more importantly to avoid having dozens of separate resx files that clash with DRY principle). I got it working with IStringLocalizer for controllers and views, but I just can't figure out how to implement it for model's data annotations.
It works by using separate files like Models.AccountViewModels.LoginViewModel.en.resx, but how would I go and use shared resource file for data annotations instead of specific ones? Can anyone share example of implementation?
P.S. Environment is .NET Core 1.1 so both validation and display annotations should be in that version available for localization

Step 1: Create a simple class, named ValidationMessages.cs and leave it empty. I will assume that your class is located in /Validation folder.
Step 2: Modify provider for data annotations localizer in your Startup.cs file to be like this:
mvcBuilder.AddDataAnnotationsLocalization(options =>
{
options.DataAnnotationLocalizerProvider = (type, factory) =>
{
return factory.Create(typeof(ValidationMessages));
};
});
Step 3: Create folder /Validation in /Resources (I assume that you are keeping all resource files in that folder) and then add ValidationMessages.fr-FR.resx file there (for French culture i.e.).
Step 4: Add entries to the resource files with keys of your liking. I assume that you will have keys like RequiredError, MaxLengthError, etc.
Step 5: Decorate properties on your model class with [Required(ErrorMessage="RequiredError")].
Next time property validation fails, validation messages will be pulled from ValidationMessages.{culture}.resx files.
Keep in mind though, that not only validation messages will be searched there, but also property names if you use DisplayAttribute.

Related

Defining Symfony Services to maximize maintainability

I'm working on a big domain, for which maintainability is very important.
There are these general workers called ExcelHandlers that implement ExcelHandlerInterface (more on the interface in the ideas section) and basically get an UploadedFile as their input, upload them wherever they want and return the read data as an associative array. Now I have created this base class ExcelFileHandler which does all of these tasks for all excel files given two arguments:
1. The Directory to upload the file
2. the mapping of the excel columns to the indexes of the associative array.
Some ExcelHandlers might have to extend the ExcelFileHandler and do some more processing, in order to get the associative array of data.
The UploadedFile is always passed to the ExcelHandler from the controller.
Now here is the question. Given the generic structure of the ExcelFileHandler how should I define services for specific ExcelHandlers given that some only differ with the original one in the directory to upload the file and the mapping array.
My Ideas:
1. The first approach involves giving the directory and the mapping as the function arguments to ExcelHandleInterface::handle this will make the prototype something like handle(UploadedFile $file, array $mapping, $dir), $mapping and $dir are given to the function as arguments and passed to the handler by the controllers which has the parameters as constructor injections.
2.1 Defining the prototype of handle to be handle(UploadedFile $file), this would require the ExcelHandlers to have knowledge of $dir and $mapping. $dir will always be injected from the constructor.
2.1.1 Foreach individual ExcelHandler in the application, define a separate class e.g: UserExcelHandler, ProductExcelHandler, .... Which extend the ExcelFileHandler and leaves us again with two choices.
2.1.1.1 inject $mapping from outside. e.g:
// in the child class
public function __construct($dir, $mapping){
parent::__construct($dir, $mapping);
}
2.1.1.2 define $mapping in the constructor of the child class. e.g:
// in the child class
public function __construct($dir){
$mapping = array(0 => 'name', 1 => 'gender');
parent::__construct($dir, $mapping);
}
2.1.2 Not to create a class for each separate ExcelHandler and instead define the ExcelFileHandler as an abstract service and decorate with the right parameters to get the concrete ExcelHandler Service with the desired functionality, obviously ExcelHandlers with custom logic must be defined seperately, and to create a uniform code base, $mapping will always be injected from the Container in this case.
In your experience, what other paths can I take and which ones yield better results in the long term?
First of all, it seams as you've already put two separate things into one.
Uploading a file and reading it's contents are two separate concerns, which can change separately (like you said, $directory and $mapping can change case-by-case). Thus I would suggest to use separate services for uploading and reading the file.
See Single responsibility principle for more information.
Furthermore, due to very similar reasons, I would not recommend base classes at all - I'd prefer composition over inheritance.
Imagine that you have 2 methods in your base class: upload, which stores file to a local directory, and parse, which reads excel file and maps columns to some data structure.
If you need to store file in a remote storage (for example FTP), you need to override upload method. Let's call this service1.
If you need to parse file differently, for example combining data from 2 sheets, you need to override parse method. Let's call this service2.
If you need to override both of these methods, while still being able to get service1 and service2, you're stuck, as you'll need to copy-and-paste the code. There's no easy way to use already written functionality from (1) and (2).
In comparison, if you have interface with upload method and interface with parse method, you can inject those 2 separate services where you need them as you need them. You can mix any implementations of those already available. All of them are already tested and you do not need to write any code - just to configure the services.
One more thing to mention - there is absolutely no need to create (and name) classes by their usage. Name them by their behaviour. For example, if you have ExcelParser, which takes $mapping as an argument to a constructor, no need to call it UserExcelParser if the code itself has nothing to do with users. If you need to parse data from several sheets, just create SheetAwareExcelParser etc., not ProductExcelParser. This way you can reuse the code. Also correct naming lets understand the code more easily.
In practice, I've seen when function or class is named by it's usage, and then it's just used in another place with no renaming, refactoring etc. These cases are really not what you're looking for.
Service names (in another words concrete objects, not classes), can of course be named by their purpose. You just configure them with any required functionality (single vs separate sheets etc.)
To summarize, I would use 2.1.2 above all other of your given options. I would inject $dir and $mapping via DI in any case, as these do not change in runtime - these are configuration.

Is it possible to place custom values (properties) in ejb-jar.xml?

1) We are using OpenEJB (both embedded and standalone) with a few deployed EJBs. We would like to specify some simple static business rules and values (example: icon_size=200). Normally, we would put them in a regular properties file (example: rules.properties). Since we shouldn't access the file system directly while inside the application server, is is possible to place those key-value pairs somewhere inside the ejb-jar.xml?
2) If not, is there a standard mechanism to do this? What is it?
Thanks
Use env-entry. In XML:
<env-entry>
<env-entry-name>icon_size</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>200</env-entry-value>
</env-entry>
In annotation:
#Resource(name="icon_size")
int icon_size;
I personally just use a .properties file; well a TernarySearchTree which reads in .properties and .XML files and allows quick retrieval. These files are available at application level. However you can in EJB 3 inject env-entry elements into your EJB. This link explains it in good detail Injection of env entry
There are some OpenEJB extensions here that might be useful.
env-entries.properties
Check out the Custom Injection example which is basically allows the <env-entry> to be specified as plain properties in a META-INF/env-entries.properties file. Nice for collapsing all those name & value pairs into a simple properties file. Internally, we just generate the xml for you using those properties. The default type is always java.lang.String, which is good for this next part.
java.beans.PropertyEditor support
Any <env-entry> which is of <env-entry-type> java.lang.String will automatically have its type converted using the VM java.beans.PropertyEditor for the target type. That's also how Spring does the converting. There are few built-in converters, such as #Resource java.util.Date myDate and #Resource java.io.File myFile

Unity2.0 - Is it possible to specify assemblies and namespaces for type lookup programatically?

I am using Unity2 with XML configuration. It has the neat feature to specify namespaces and assemblies in the XML config for which automatic type lookup is performed, so that you do not need to always specify full name or create an alias.
Is it possible to specify assemblies and namespaces for the automatic type lookup programatically, without them being explicitly listed in the XML configuration? My goal is to simplify the XML configuration for my application's administrators. Types from two or three namespaces will almost always be used in the container registrations, so I would like these namespaces to be included in the lookup automatically.
There's nothing built in explicitly to support this.
An option would require a few more steps in your code. instead of just calling container.LoadConfiguration(), you'd instead explicitly grab the configuration section:
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
Then, you'd go into the Namespaces or Assemblies properties on the section, and add new NamespaceElement or AssemblyElement objects pointing at the "standard" namespaces and assemblies. Then you apply the updated configuration section to the container. Something like this:
section.Namespaces.Add(new NamespaceElement() { Name = "my.standard.namespace" });
container.LoadConfiguration(section);
I haven't actually tried this, :-), but it should work.

Entity Container and Model generation in different assemblies

I'm doing some refactoring and am trying to reuse my genertated entity models. My application has a few assemblies, one being my outward facing public types (API) and one containing implementations of providers (such as the log).
I'd like to split the generation of the entities and models so that the entities will be in the API assembly and the container will be in the implementation assembly. Is this possible?
Is possible. This is how I did it.
Assembly A
Database.EDMX
Models.TT
Models.cs
Assembly B
Database.EDMX (Added as a Link to the real file in Assembly A)
EntityContainer.TT
EntityContainer.cs
That's how everything is laid out. These are the rough steps:
Right click on the EDMX in A (public API assembly) and Add Code Generation File
Adds a TT to the project. Called it Models, as it will contain the models only.
Edited the TT and removed code generation for entity containers
In assembly B (internal implementations) added Database.EDMA as a link
Opened in assembly B, right click and Add Code Generation File
Adds a TT to project B. Called it EntityContainer as it will contain that only.
Edited TT to do the following
Removed entity creation steps
Changed the path to Database.EDMX to a relative path pointing at the original copy in A
Added a using for my models
Hopefully this will all compile and work correctly (I'm still far from getting everything compiled and tested). Looks good so far.
Additional change:
In my entity container TT, I had to modify the definition of the EscapeEndTypeName to the following:
string EscapeEndTypeName(AssociationType association, int index,
CodeGenerationTools code)
{
EntityType entity = association.AssociationEndMembers[index]
.GetEntityType();
return code.CreateFullName(
code.EscapeNamespace(association.NamespaceName), code.Escape(entity));
}
I'm using association.NamespaceName as it contains the correct namespace from the other assembly.
I don't know the answer, but I think that your question is essentially equivalent to "Is it possible to cause a T4 template in one project to emit code into a different project?" If you can do that, then you can do what you want. Note, though, that this is substantially easier in EF 4.
So I think you might get useful feedback if you asked that question directly.

how can i use structure map asp.net 3.5

I am new to the structure map but i want to use it in my asp.net site for dependency injection
can any one suggest me simple example to use structure map for the dependency injection
you will need to do something like this:-
StructureMapConfiguration
.ForRequestedType<IResourceA>()
.TheDefaultIsConcreteType<ResourceB>()
.CacheBy(InstanceScope.Singleton);
This tells StructureMap to inject ResourceB when there is a request for ResourceA.
Structure Map
You can configure programatically or via configuration file.
Programatical example (there are other ways):
StructureMap.StructureMapConfiguration.ForRequestedType<ISomething>().TheDefaultIsConcreteType<ConcreteSomething>();
then you can get an instance of the configured type using this sort of code:
//The concrete type will be ConcreteSomething
ISomething instance = ObjectFactory.GetInstance<ISomething>();
You can do it in a config file:
<StructureMap MementoStyle="Attribute">
<DefaultInstance PluginType="Blah.ISomething, Blah.SomethingDLL" PluggedType="Blah.Concrete.ConcreteSomething,Blah.ConcreteDLL"/>
</StructureMap>
and in the main method or Global.asax you can set this config by saying:
StructureMap.ObjectFactory.Initialize(x => { x.PullConfigurationFromAppConfig = true; });
and use it the same way as above:
ISomething instance = ObjectFactory.GetInstance<ISomething>();
If the concrete class has a constructor that needs instances injected in it, and you have those configured, the concrete types will get injected by the framework.
There are ways of passing parameters to constructors, dealing with Gereric types, creating named instances that are configured with specific constructor/property values. I use this framework and like it very much.

Resources