ASP.NET localization: Changing resources without r

2019-04-29 03:18发布

问题:

I have the requirement that the end-user can change localized resources and the changes should be visible in the application without the need to restart the application.

Update to clarify the scenario:
I am talking about changing the localized resources at runtime. Lets say I have a typo in the german translation of a page. Then some admin-user should have the possibility to change that typo at runtime. There should be no need for a redeployment or restart in order for this change to be reflected in the UI.

I am using ASP.NET MVC3.

What options do I have?

I have been looking into writing a custom ResourceProvider that loads resources from the database.
This seems not too much effort, however so far I pointed out two drawbacks:

  • It is not working with the DataAnnotations that are used for convenient validation in MVC3 (DataAnnotations work with a ErrorMessageResourceType parameter, which only works with compiled resources)
  • We basically have to provide our own tooling around managing resources (like translating etc.) which is a pity, since there are a lot of tools for this that work with resx-files.

What are the other options? Would manipulation of the deployed resx-files at runtime be an option?
But I suspect that the application is automatically "restarted" when it detects those changes: I suspect ASP.NET realizes that the resx-files have changed, it then recycles the application-pool and compiles the new resx-files on the fly.
Is this correct? Is there any way around this?

I have not yet looked into compiling the resources into satellite assemblies before deployment. Is this even a recommended scenario for web applications?
But even with compiled satellite assemblies I suspect that ASP.NET restarts the application, when those assemblies are changed on the fly. Is this correct?

I would be interested in any experience in how the original requirement can be satisfied? And I would be interested in any comments about the options I have mentioned above.

回答1:

DataAnnotations accept a ErrorMessageResourceType which tells the ValidationAttrributes where to access resources. You can pass this as follows:

[Required(
    ErrorMessageResourceType = typeof(DynamicResources), 
    ErrorMessageResourceName = "ResourceKey")]
public string Username { get; set; }

By creating a type for this parameter with static properties for each key you can create an implementation that loads resources from a database or other implementation. You could then combine this with a dynamic object for DRY and move the implementation into TryGetMember. Potentially then use T4 templates to generate the statics from your database at compile time, ending up with this:

public class DynamicResources : DynamicObject
{
    // move these into partial and generate using T4
    public static string MyResource
    {
        get { return Singleton.MyResource; }
    }

    public static string MyOtherResource
    {
        get { return Singleton.MyOtherResource; }
    }

    // base implementation to retrieve resources
    private static dynamic singleton;

    private static dynamic Singleton
    {
        get { return singleton ?? (singleton = new DynamicResources()); }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        // some logic here to look up resources
        result = GetResourceKeyFromDatabase(binder.Name);
        return true;
    }
}

Of course it would be perfect if resources weren't static properties.