Bug 1400978

Summary: s2i build renames the project assembly
Product: dotNET Reporter: Tom Deseyn <tdeseyn>
Component: rh-dotnetcore10-containerAssignee: Severin Gehwolf <sgehwolf>
Status: CLOSED ERRATA QA Contact: jiri vanek <jvanek>
Severity: unspecified Docs Contact: Les Williams <lwilliam>
Priority: unspecified    
Version: 1.0CC: bgollahe, dbhole, kanderso, lzachar, omajid, sgehwolf, zzambers
Target Milestone: ga   
Target Release: 1.0   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: rh-dotnetcore10-docker-1.0-13 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2017-03-20 08:24:57 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Tom Deseyn 2016-12-02 13:26:26 UTC
.NET Core projects are in a folder. When they are compiled the resulting assembly has the name of the folder + dll. E.g. MusicStore -> MusicStore.dll.

When using the contextDir to specify the location of the project folder, this folder is renamed to 'src' inside the docker container. As a consequence, the assembly name is src.dll.

The code may actually rely on the assembly name. For example the ASP.NET Core WebHostBuilder has a UseStartup method which takes an assembly name.

The ASP.NET MusicStore is using that method, which no longer finds the assembly because it has been renamed from MusicStore to src.

```
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'MusicStore, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks, IntPtr ptrLoadContextBinder)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks, IntPtr ptrLoadContextBinder)
   at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
   at Microsoft.AspNetCore.Hosting.Internal.StartupLoader.FindStartupType(String startupAssemblyName, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.<>c__DisplayClass14_1.<BuildCommonServices>b__2(IServiceProvider _)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureStartup()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
```

Comment 1 Tom Deseyn 2016-12-06 09:38:16 UTC
I think we want to support a typical repository. Such a repository will contain: a project which represents the runnable app. One or more library projects which are consumed by the runnable app. One or more test projects which contain unit tests.

First step is to restore dependencies for the projects.

The dotnet restore command accepts a parameter called root which tells it what projects to restore. We can expose this as an envvar: RESTORE_ROOT and default to '.' when unspecified. This value will recursively find all project.json files and restore their dependencies.

The dotnet tooling can figure out which dependencies a project has. So we only need to build the runnable app project. This should be another envvar: PROJECT/STARTUP_PROJECT. The value of this envvar is a folder name. Inside this directory we will cd and run the dotnet build command. This envvar must be provided by the user.

To support running the unit tests in the repository, we can add a TEST_PROJECTS envvar. This envvar should be set to a 'list' of folder names. The s2i test would cd into each folder and execute 'dotnet test'.

Comment 2 Omair Majid 2016-12-06 14:36:27 UTC
I am not an expert with .NET Core, so please excuse my mistakes.

> I think we want to support a typical repository. Such a repository will contain: a project which represents the runnable app. One or more library projects which are consumed by the runnable app. One or more test projects which contain unit tests.

For simpler demos like Hello World, perhaps we should consider relaxing the above to: a project which represents the runnable app, zero or more library projects and zero or more test projects?

Other comments:

If PROJECT/STARTUP_PROJECT is unset, is defaulting to "." sensible? Or is this only going to happen for toy applications and never a real-world use-case?

We don't currently run `dotnet test` at any point. Do you expect it to become part of s2i workflow?

Comment 3 Tom Deseyn 2016-12-06 15:00:21 UTC
I am fine with defaulting PROJECT/STARTUP_PROJECT to ".". I don't expect this to happen on a production-grade app. But as you point out, for simple demos it will work out of the box then.

Tests make sense as part of the general s2i workflow, so I think we want to support this for dotnet too.

Are you okay with the proposed envvar names? Do you have a preference between PROJECT or STARTUP_PROJECT?

Comment 4 Gary Piercey 2016-12-06 15:26:23 UTC
A reasonable use case for supporting tests is for CI & CD. I agree that we should support this as well.

To remain consistent with the other env vars in those scripts maybe we could use something like DOTNET_STARTUP_PROJECT and DOTNET_ROOT. It doesn't really matter as long as it is clear what they need to be used for.

Comment 5 Omair Majid 2016-12-06 15:43:12 UTC
Does OpenShift target CI or testing? Looking at other s2i images [1][2], none of them provide a way to run the tests (or do they?). The testing support that I see is more about testing the s2i images themselves.

[1] https://github.com/sclorg/s2i-ruby-container/search?p=1&q=test&utf8=✓
[2] https://github.com/sclorg/s2i-python-container/search?utf8=✓&q=test

Comment 6 Gary Piercey 2016-12-06 16:06:55 UTC
It looks like testing is supported by s2i optional scripts:
https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md#s2i-scripts

The situation I was considering is for multi-platform testing where we would want to use virtualization to run tests across multiple platforms or against different versions of libraries or frameworks for compatibility. For this I think OpenShift and s2i are quite well suited because a CI/CD application can easily script the running of these tests using templates and the OpenShift CLI.

Comment 7 Tom Deseyn 2016-12-06 19:20:21 UTC
Had a closer look at the OpenShift documentation. The s2i test script is indeed intended for testing the s2i image and not for testing the application. Testing the application should be done using "build hooks". So let's drop the TEST_PROJECTS.

Comment 8 Tom Deseyn 2016-12-12 14:09:07 UTC
I sent an e-mail to Ben Parees about this.
Next to the post-commit option, starting unit tests from the assemble script is also an option. He mentions the fact that "it doesn't requires all your test code/framework be part of the final image though, which obviously may be undesirable". He is referring here to the "multiple-step build processes" as described on https://github.com/openshift/source-to-image.

Created ticket: https://bugzilla.redhat.com/show_bug.cgi?id=1403867

Comment 13 errata-xmlrpc 2017-03-20 08:24:57 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2017:0560