Skip to content
This repository was archived by the owner on Nov 29, 2018. It is now read-only.

Application parts, MissingManifestResourceException: The manifest 'Xxx.Yyy.Zzz.en.resources' was not found #281

Closed
DmitrySikorsky opened this issue Sep 12, 2016 · 20 comments

Comments

@DmitrySikorsky
Copy link

I'm working on modular application and trying to add application part (assembly 'Module') to the main application (assembly 'Application'). Also I have direct link to that project in Application's project.json.

Module contains localized views (using IViewLocalizer) and resx files in the Resources folder. Values from the resx not shown. If I try to call IViewLocalizer's GetAllStrings method in the View I will get next exception:

MissingManifestResourceException: The manifest 'Application.Resources.Views.Cultures.Index.en.resources' was not found.

Why does it look for Application.Resources but not for Module.Resource? I have checked and there is Module.Resources.Views.Cultures.Index.en.resources available inside the Module assembly.

Could you please help me with that? Thanks!

@hishamco
Copy link
Contributor

I think it's a duplicate for issue #257

@DmitrySikorsky
Copy link
Author

Maybe. GetManifestResourceNames() returns nothing (except views) for me too. But I know that resource is added because if I add resx like A.B.C.resx in addition to A/B/C.resx I get compilation error that resource id is already exists.

Problem is that I'm not sure that I'm doing this in the right way. Localization works if I have localized views and resx in the Application project, but it doesn't work in the views from separate assembly. (Just does nothing or throughs exception if I call GetAllStrings). Is it enough just to add localized views and resx in the Module project and then use AddApplicationPart to add that assembly?

@hishamco
Copy link
Contributor

Localization works if I have localized views and resx in the Application project, but it doesn't work in the views from separate assembly.

This is seems a bug in 1.1.0-alpha1-21873, please have a look to this issue #275

@DmitrySikorsky
Copy link
Author

Problem is that I'm using 1.0.0. I will try to create simple demo for you.

@Eilon
Copy link
Contributor

Eilon commented Sep 14, 2016

We think we have a way of making this fairly easily doable in an app:

  1. We'll define a new assembly-level attribute [assembly: LocalizerResourcePath(string resourcePath)]
  2. Assemblies such as those containing application parts would use this new attribute to specify their root resource path.
  3. The default localization system would check the type of the resource being used, see if its containing assembly has this attribute, and if so, use that as the resource root path for lookups. If the attribute isn't there, then the current behavior will be used, which is that the localization Options class has its own resource path.

@kevinchalet
Copy link

@Eilon great approach (similar to the one I had in mind).

In a perfect world, one should also be able to override the resources used by a "class library", but it's probably too much to ask, right? 😄

@Eilon
Copy link
Contributor

Eilon commented Sep 15, 2016

@PinpointTownes that's certainly debatable. Usually resources are an implementation detail of a class library and so it doesn't make sense to allow someone to modify it from outside.

But in the case where the author of the "app" and the "class library" is the same person, it certainly gets more interesting. But no plans to support that at this time 😄

@kevinchalet
Copy link

kevinchalet commented Sep 15, 2016

But in the case where the author of the "app" and the "class library" is the same person, it certainly gets more interesting.

Nah, actually, that's not what I had in mind.

Here's a concrete use case: in ASOS/OpenIddict, we use a bunch of OpenID error messages that are returned to OIDC apps or directly to users. Currently, these messages are hardcoded but a few people said they were interested in localizing/customizing them (e.g aspnet-contrib/AspNet.Security.OpenIdConnect.Server#240 (comment)).

Allowing one to override the [assembly: LocalizerResourcePath(string resourcePath)] directive would enable a few interesting scenarios like adding languages that are not supported by the library author or customizing strings.

I suppose it would be as simple as adding a property to LocalizerResourcePathAttribute:

// Specify Overridable = true to allow the app writer to override the resource strings used by this assembly. 
[assembly: LocalizerResourcePath("path", Overridable = true)]

@DmitrySikorsky
Copy link
Author

To be able to use static resources (like images) from other assemblies I create CompositeFileProvider like this: https://github.com/ExtCore/ExtCore/blob/master/src/ExtCore.Mvc/MvcExtension.cs#L122

Maybe we could have something like that for localization too? To unify the approaches. Like to define assemblies to look for localizations in?

@joeaudette
Copy link

this is the same problem I was trying to tackle in this project
https://github.com/joeaudette/cloudscribe.Web.Localization

it would be nice if the framework provided a way to solve this problem without so much workaround

for me the main web app is like the assembly point where composition root and configuration live, but most functionality is going to be in separate class library projects, whether using class libraries I wrote myself or written by others I want to be able to affect the localization from the main web app and to be able to customize in addition to localize. otherwise the difficulty of localizing those separate projects kind of pushes one towards baking most things directly in the main web app where it is easier to localize and customize (at least for the code by a single author)

@Eilon
Copy link
Contributor

Eilon commented Sep 15, 2016

@PinpointTownes I'm not sure I like that pattern for overriding another component's resources. It seems very fragile because it's not clear the intention of each resource. It also assumes using a specific localization technology and pattern, which might not work for everyone.

Instead, I recommend a first-class approach such as what we do in Identity here: https://github.com/aspnet/Identity/blob/dev/src/Microsoft.AspNetCore.Identity/IdentityErrorDescriber.cs#L12

There's a service with methods for each possible error, and they can be parameterized as well.

@kevinchalet
Copy link

It seems very fragile because it's not clear the intention of each resource.

I'm not sure I understand. My suggestion has nothing to do with the resource itself, but with its location (i.e being able to tell the localization stack that resource "xyz" will come from the "entry point app" instead of a specific class library.

@Eilon
Copy link
Contributor

Eilon commented Sep 15, 2016

@PinpointTownes it assumes that the loc system is using embedded resources. But some libraries and/or sites might be using PO files, a database, a dynamic system, etc.

@joeaudette
Copy link

to me the part that seems fragile is the way any arbitrary location can be set like this in the main web app:

services.AddLocalization(options => options.ResourcesPath = "FooResources");

Instead of that if there could be a specific well known folder name where resx files could live and that would allow overriding resx resources from class libraries as well as the main app would be ideal. Sort of but not exactly like the old special folder App_GlobalResources

@ryanbrandenburg
Copy link
Contributor

ryanbrandenburg commented Sep 23, 2016

This should be enabled by #283. If you still have any problems feel free to reopen, closing until then.

@DmitrySikorsky
Copy link
Author

Hi! I'm trying to make it work but still with no luck. I have created simple test project: https://github.com/DmitrySikorsky/AspNetCoreSeparatedLocalization

It will work if I move the SharedResources class from the AspNetCoreSeparatedLocalization project to the AspNetCoreSeparatedLocalization.Shared one, but I need it to be located in the AspNetCoreSeparatedLocalization project (it will be not only SharedResources class, but controllers etc.)

What I am doing wrong? Thank you for the answer!

@hishamco
Copy link
Contributor

hishamco commented Nov 1, 2016

I'm asking why you wanna move the SharedResources to AspNetCoreSeparatedLocalization instead of AspNetCoreSeparatedLocalization.Shared?

@DmitrySikorsky
Copy link
Author

DmitrySikorsky commented Nov 1, 2016

The main project is web application that contains controllers etc. The second project is resources one that contains only resources. SharedResources class is just a sample, I would use controllers etc. So that's why I can't put it to the resources project. Also I would like to have resources separated to be able to add them like 3d party components (in modular systems like my ExtCore project).

UPD: also I will need to use localization in the application parts assemblies, so the assemblies will contain controllers and resources at the same time.

@ryanbrandenburg
Copy link
Contributor

The current design requires that a Resource you want to look up by its type be in the same assembly as that type. This prevents us from having to go digging through every assembly in the project to find resources.

My first recomendation is to just keep the Resources in the same project as their types, but if it's important to you that your resources be in a project seperate from the types they represent you have two options:

  1. Construct your localizer using IStringLocalizerFactory.Create(string baseName, string location) which would give you the ability to specify the location (assembly) seperate from the baseName (Type).
  2. Write your own implementation of IStringLocalizerFactory which understands your specific requirements.

Also of note here is that your projects appear to have been renamed from AspNetCoreSeparatedResources to AspNetCoreSeparatedLocalization. It's very important to note that renaming the project in VS will NOT change the namespaces or [assembly: AssemblyProduct()] and so on. It is up to you to do these things and make sure that the resources you've created still match up.

@DmitrySikorsky
Copy link
Author

Thank you for your answer, now it is very clear, I will think what option to choose.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants