Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Resource Assembies from Referenced Assemblies are not loaded
Der-Albert.com
#1 Posted : Thursday, November 15, 2018 12:33:38 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 5/17/2011(UTC)
Posts: 138

Thanks: 3 times
Was thanked: 24 time(s) in 22 post(s)
I have a .NET Assembly, which contains resources. And I have a dotnet core 2.1 UnitTest Project.

In the Unit Test i try to access the resources. this works fine in Visual Studio, ReSharper and via dotnet test.

But not in NCrunch, if i look in the temp folder of NCrunch then the satellite resource assemblies are missing.

Code:

    public class ResourceTests
    {
        readonly ServiceProvider _provider;

        public ResourceTests()
        {
            // Only to avoid complicated mocking
            var services = new ServiceCollection();
            services.AddOptions(); 
            services.AddLogging();
            _provider = services.BuildServiceProvider();
        }


        /// this works in ncrunch
        [Fact]
        public void LocalResources_should_be_resolver()
        {
            var factory = ActivatorUtilities.CreateInstance<ResourceManagerStringLocalizerFactory>(_provider);

            var localizerEn = factory.Create(typeof(LocalResource));
            var localizerDe = factory.Create(typeof(LocalResource)).WithCulture(new CultureInfo("de-DE"));

            Assert.NotEmpty(localizerEn.GetAllStrings());
            Assert.NotEmpty(localizerDe.GetAllStrings());
        }

        /// this does not works in ncrunch - but works in VS, with dotnet test and with ReSharper
        [Fact]
        public void ExternalResources_should_be_resolved()
        {
            var factory = ActivatorUtilities.CreateInstance<ResourceManagerStringLocalizerFactory>(_provider);

            var localizerEn = factory.Create(typeof(ExternalResource));
            var localizerDe = factory.Create(typeof(ExternalResource)).WithCulture(new CultureInfo("de-DE"));

            Assert.NotEmpty(localizerEn.GetAllStrings());
            Assert.NotEmpty(localizerDe.GetAllStrings());
        }

    }


Result of dotnet test

Code:

λ  dotnet test
Build started, please wait...
Build completed.

Test run for C:\dev\private\NCrunchNETCoreLocalizationTests\NCrunchNETCoreLocalizationTests\bin\Debug\netcoreapp2.1\NCrunchNETCoreLocalizationTests.dll(.NETCoreApp,Version=v2.1)
Microsoft (R) Test Execution Command Line Tool Version 15.9.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

Total tests: 2. Passed: 2. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 1,8353 Seconds
C:\dev\private\NCrunchNETCoreLocalizationTests\NCrunchNETCoreLocalizationTests

Here is the Sample solution
https://1drv.ms/u/s!AmXNl8dqs5HUpMpSHg7qHwCfZsciyQ
Der-Albert.com
#2 Posted : Thursday, November 15, 2018 12:37:53 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 5/17/2011(UTC)
Posts: 138

Thanks: 3 times
Was thanked: 24 time(s) in 22 post(s)
Yes, i can fix this with adding the additional assemblies. But this sucks, because I think this should be a standard scenario.
Der-Albert.com
#3 Posted : Thursday, November 15, 2018 1:15:12 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 5/17/2011(UTC)
Posts: 138

Thanks: 3 times
Was thanked: 24 time(s) in 22 post(s)
Also, i add the missing assemblies in the ncrunch configuration for the test project, the satellite assemblies get not updated reliable and have old values in there (after saving the resource files files, and running tests again, even manually). But there seems only dotnet test run fine. even resharper and visual studio have problems with that.
Der-Albert.com
#4 Posted : Thursday, November 15, 2018 1:52:31 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 5/17/2011(UTC)
Posts: 138

Thanks: 3 times
Was thanked: 24 time(s) in 22 post(s)
Ok, i can added the assemblies from the source assembly folder, i had to add the assemblies from the test assembly folder (bin/netcoreapp2.1/debug) to make it work, which also explains the update problem.
Remco
#5 Posted : Thursday, November 15, 2018 10:58:43 PM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 5,476

Thanks: 717 times
Was thanked: 898 time(s) in 854 post(s)
Thanks for sharing this problem.

This looks to be a classic case of framework code assuming that dependency DLLs are collocated with the project's output assembly. Turning on the 'Copy referenced assemblies to workspace' seems to resolve this problem.

The root of the issue is that the ResourceManagerStringLocalizerFactory assumes that 'TheLibrary.dll' is sitting adjacent to 'nCrunchNETCoreLocalizationTests', which just isn't the case when you're working with NCrunch's optimised build.

There are two ways to solve this problem:

1. Turn on 'Copy referenced assemblies to workspace' then deal with the degraded performance that comes with this setting

2. Find a way to tell the ResourceManagerStringLocalizerFactory where to load the external resources from. It looks like this class has an alternative constructor that allows you to inject an option specifying relative file path. Could it be possible to force it to load from somewhere else?
https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.localization.resourcemanagerstringlocalizerfactory.-ctor?view=aspnetcore-2.1
https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.localization.localizationoptions?view=aspnetcore-2.1
Der-Albert.com
#6 Posted : Thursday, November 15, 2018 11:52:27 PM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 5/17/2011(UTC)
Posts: 138

Thanks: 3 times
Was thanked: 24 time(s) in 22 post(s)
Hi Remco,

for 1. Yes, copy reference assemblies works. But this may degrade performance. For this i have a question, for me as a none native english speaker I have
little trouble to be sure about this description in the docs

NCrunch must rebuild all upwards dependencies from the project that has changed.

In this sample, i have enabled that for the test project. But which projects will be rebuilds if i change in the test project, besides the test project?

a) Upwards in the hierarchy (if i move a member member of a class up, the it get's moved to the base class) e.g. the TheLibrary and Every other dependencies which is
referenced, or b) upwards on the dependencies e.g. Projects that depends on the Test project (e.g. none).

For a) in this repo project, this is not a problem, but in the real project. b) should be no problem at all, but then, why is the performance problem even mentioned

for 2. this path is for adapting the namespace where the resources are placed.

But

on a normal Compile (dotnet build) the resource assemblies are placed in folder for their language.
This also happends with copying the reference assemblies.

TheLibrary
Code:

TheLibrary/bin/debug/netcoreapp2.1/de/TheLibrary.resources.dll
TheLibrary/bin/debug/netcoreapp2.1/en/TheLibrary.resources.dll


Test Project
Code:

NCrunchLocalizationTests/bin/debug/netcoreapp2.1/de/TheLibrary.resources.dll
NCrunchLocalizationTests/bin/debug/netcoreapp2.1/de/NCrunchLocalizationTests.resources.dll
NCrunchLocalizationTests/bin/debug/netcoreapp2.1/en/TheLibrary.resources.dll
NCrunchLocalizationTests/bin/debug/netcoreapp2.1/de/NCrunchLocalizationTests.resources.dll


This is the normale place for the satellite assemblies.

I in don't set copy references assemblies this is the result in the ncrunch folder build folders

TheLibrary
Code:

TheLibrary/bin/debug/netcoreapp2.1/de/TheLibrary.resources.dll
TheLibrary/bin/debug/netcoreapp2.1/en/TheLibrary.resources.dll


Test Project
Code:

NCrunchLocalizationTests/bin/debug/netcoreapp2.1/de/NCrunchLocalizationTests.resources.dll
NCrunchLocalizationTests/bin/debug/netcoreapp2.1/de/NCrunchLocalizationTests.resources.dll


So, even if would be able to change the path from where the resource assemblies are loaded at test time, it would
not be possible because these satellite assemblies are not even in reach for the test project.
These are only living in the an unknown folder where TheLibrary ist build.

I would assume that *.resx are not file a special case, and the NCrunch may can do better on copying the resources assemblies from the library to the test project ;)
Remco
#7 Posted : Friday, November 16, 2018 2:00:50 AM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 5,476

Thanks: 717 times
Was thanked: 898 time(s) in 854 post(s)
When the 'Copy Referenced Assemblies to Workspace' setting is enabled for a project, NCrunch will always copy its references to the project build output directory. This means that TheLibrary.dll lands inside NCrunchNETCoreLocalizationTests\bin\Debug\netcoreapp2.1, and its satellite assemblies are also accordingly underneath this path.

Because both TheLibrary and its satellite assemblies now need to be copied by MSBuild into the output directory for NCrunchNETCoreLocalizationTests, it isn't possible for us to make any kind of code change to TheLibrary without re-copying its output files into the output directory of NCrunchNETCoreLocalizationTests. The copying of these files is handled by build steps inside the NCrunchNETCoreLocalizationTests project. Therefore, whenever TheLibrary is changed, NCrunchNETCoreLocalizationTests must be rebuilt. This is the normal behaviour for MSBuild, which under NCrunch we try to suppress by default because we can provide test results faster when we only need to build a minimal number of projects after the code is changed.

When there are other projects referencing NCrunchNETCoreLocalizationTests, the issue gets bigger, because any code running in these projects would likely be using the same resource code in NCrunchNETCoreLocalizationTests, and therefore would have the same constraints. So these projects would likely need to be rebuilt too. So instead of building just TheLibrary when it changes, we need to build TheLibrary and everything else that depends on it. Then everything else that depends on that. Once again, this is the default behaviour of MSBuild, and it's one of the main reasons why NCrunch is able to run tests so much faster than other runners. When possible we try to be more selective with what we build.

You could make the argument that the resolution of resources at run time is extremely common, so NCrunch should implement a special mechanism to handle copying of these resources to referencing projects without the need for a build step. Such a thing could certainly be implemented, but it would be very challenging and expensive to do so, because it involves breaking a number of abstractions in the build system that would further expose us to breaking changes introduced at platform level. From the side of NCrunch, a better solution would be to instead find ways of improving performance in general so that we can build projects faster.

Above all, the best solution would be to find a way to tell the ResourceManagerStringLocalizerFactory where it needs to look for the assembly it's trying to find. If you can find a way to pass the path of the dependency into this component, the problem is entirely resolved. You can easily find the resource assemblies by using the location of the assemblies NCrunch has already loaded into the current application domain (i.e. typeof(ExternalResource).Assembly.Location). Alternatively, you can use the routines in NCrunch.Framework to find them. Here's some more information about how this can be done.
1 user thanked Remco for this useful post.
Der-Albert.com on 11/22/2018(UTC)
Der-Albert.com
#8 Posted : Thursday, November 22, 2018 8:40:36 AM(UTC)
Rank: Advanced Member

Groups: Registered
Joined: 5/17/2011(UTC)
Posts: 138

Thanks: 3 times
Was thanked: 24 time(s) in 22 post(s)
Ok, currently their are no other projects referencing the tests project (i prefer not to to that).

For that i can live with that quirks. It's not worth to mess up with assembly resolving and my introduce other side effects.

Thanks for the answer.
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

YAF | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.085 seconds.