Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hosting startup topic updates #7678

Merged
merged 21 commits into from
Aug 31, 2018
Merged

Conversation

guardrex
Copy link
Collaborator

@guardrex guardrex commented Jul 18, 2018

Fixes #6896

Internal Review Topic

  • Surfaces the new content in the same topic. I think this pulls it off and avoids 👹 Topic Creep™️ 👹 .
  • Sample expanded to demo a hosting startup activated from a class lib. The class lib adds some config values via AddInMemoryCollection.
  • Includes a description of the new (2.1) exclusion machinery:
    • Hosting Startup Exclude Assemblies host configuration setting.
    • ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES
  • Moves topic to host in the TOC.

@guardrex guardrex requested review from davidfowl and Tratcher July 18, 2018 20:06
@Tratcher Tratcher requested a review from pakrym July 18, 2018 23:01
Copy link
Member

@Tratcher Tratcher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[incomplete review, to-be-continued]


*HostingStartupApp/Pages/Index.cshtml.cs*:

[!code-csharp[](platform-specific-configuration/samples/2.x/HostingStartupSample/HostingStartupApp/Pages/Index.cshtml.cs?name=snippet1&highlight=11-12,19-20)]

## Discover loaded hosting startup assemblies
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related: The entry assembly or the assembly containing your Startup class is scanned by default for HostingStartup attributes. https://github.com/aspnet/Hosting/blob/864caa20b43ab33415795bd4f6c6d3a4365c8bfe/src/Microsoft.AspNetCore.Hosting/Internal/WebHostOptions.cs#L36-L37

@@ -16,12 +16,16 @@ public IndexModel(IConfiguration config)
}

public string[] LoadedHostingStartupAssemblies { get; private set; }
public string ServiceKey_Development { get; private set; }
public string ServiceKey_Production { get; private set; }

public void OnGet()
{
LoadedHostingStartupAssemblies =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't all of this done in the constructor?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine by me. I'll change it on the next commit.


*HostingStartupApp/Pages/Index.cshtml.cs*:

[!code-csharp[](platform-specific-configuration/samples/2.x/HostingStartupSample/HostingStartupApp/Pages/Index.cshtml.cs?name=snippet1&highlight=11-12,19-20)]

## Discover loaded hosting startup assemblies

To discover hosting startup assemblies loaded by the app or by libraries, enable logging and check the application logs. Errors that occur when loading assemblies are logged. Loaded hosting startup assemblies are logged at the Debug level, and all errors are logged.

The sample app reads the [HostingStartupAssembliesKey](/dotnet/api/microsoft.aspnetcore.hosting.webhostdefaults.hostingstartupassemblieskey) into a `string` array and displays the result in the app's Index page:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why we have this sample, this is not something we expect apps to do in code. Also, after aspnet/Hosting#1243 this list isn't very accurate. Also see my prior comment about your entry assembly being added to the list by default. Describe the config keys but remove the LoadedHostingStartupAssemblies code sample.

Copy link
Collaborator Author

@guardrex guardrex Jul 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was just for demo purposes. I'll remove it on the next commit.

[EDIT] There was possibly a troubleshooting aspect to my thinking on this, too. This shows that if they just look at _config[WebHostDefaults.HostingStartupAssembliesKey] they'll see the assemblies. I'll still cut it ... but just say'in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is "this list?"

@guardrex
Copy link
Collaborator Author

@Tratcher Had a few minutes here to get what you requested thus far ... it's on the last commit.

Let me know what u meant by "this list." What list?

@guardrex guardrex force-pushed the guardrex/hosting-startup-updates branch from 885eb34 to d3c666d Compare July 19, 2018 00:26

[!code-csharp[](platform-specific-configuration/samples/2.x/HostingStartupSample/HostingStartupLib/ServiceKeyInjection.cs?name=snippet1)]

The app's `Startup` class file specifies a [HostingStartup](/dotnet/api/microsoft.aspnetcore.hosting.hostingstartupattribute) attribute for the class library's `ServiceKeyInjection` class.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is atypical. Adding a direct reference from your own Startup class defeats the purpose, you could already have called that implementation directly. More commonly the app would not add the attribute to their own project, it would be in an unreferenced assembly and discovered via environment variable.

The reason we search the entry assembly is that some tooling adds HostingStartup attributes dynamically at compile time.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fails to describe the HostingStartup assembly attribute that can point to types in existing referenced libraries

I knew "referenced library" could've meant that the lib isn't in the same solution. Perhaps, I misunderstood @davidfowl's "very simple attribute" remark and his link to the repo sample to mean that the app would provide the direct reference from the Startup class ... that's what the linked repo sample shows.

unreferenced assembly and discovered via environment variable.

.... so .....

  1. Have the lib as a standalone project
  2. Compile the standalone lib
  3. bin-deploy the lib in the app
  4. Set the env var (ASPNETCORE_HOSTINGSTARTUPASSEMBLIES)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the approach we use.

One other flow may be practical to include:

  1. Have the lib as standalone project with its HostingStartup attribute.
  2. Reference that project as a dependency (typically as a nuget)
  3. Set the env var (ASPNETCORE_HOSTINGSTARTUPASSEMBLIES)

This allows nuget packages to provide startup functionality without any code changes, but you still have a compile time dependency so that removes all of the deps and deployment work.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok ... sounds good. I'll work on this tomorrow, and let's look again next week.

The sample app reads the [HostingStartupAssembliesKey](/dotnet/api/microsoft.aspnetcore.hosting.webhostdefaults.hostingstartupassemblieskey) into a `string` array and displays the result in the app's Index page:

[!code-csharp[](platform-specific-configuration/sample/HostingStartupSample/Pages/Index.cshtml.cs?name=snippet1&highlight=14-16)]
Hosting startup assemblies are listed in the [WebHostDefaults.HostingStartupAssembliesKey](/dotnet/api/microsoft.aspnetcore.hosting.webhostdefaults.hostingstartupassemblieskey). Excluded assemblies are listed in the [WebHostDefaults.HostingStartupExcludeAssembliesKey](/dotnet/api/microsoft.aspnetcore.hosting.webhostdefaults.hostingstartupexcludeassemblieskey). For more information, see [Web Host: Hosting Startup Assemblies](xref:fundamentals/host/web-host#hosting-startup-assemblies) and [Web Host: Hosting Startup Exclude Assemblies](xref:fundamentals/host/web-host#hosting-startup-exclude-assemblies).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list of assemblies to search for HostingStartup attributes is loaded from config under the HostingStartupAssemblies key. The list of assemblies to exclude from discovery is loaded from config under the HostingStartupExcludeAssemblies key.

@guardrex guardrex changed the title Hosting startup topic updates [WIP] Hosting startup topic updates Jul 20, 2018
@guardrex guardrex added the WIP label Jul 20, 2018
@guardrex
Copy link
Collaborator Author

guardrex commented Jul 22, 2018

@Tratcher I updated the topic+sample along the lines of your feedback. It has a standalone class lib scenario and a NuGet package scenario now. I go with the NuGet scenario first, as I think that might be more popular.

The paint is still wet on these updates, so I'll make anther pass Monday morning.

Three items came up along the way:

  1. I distinguish Activation from a class library from Activation from an assembly (the "additionalDeps" scenario). I don't think it's clear/correct in its present form. I guess a console app without an entry point is an "assembly." What do we call the "assembly" (console app without an entry point) that's activating the hosting startup in the "additonalDeps" scenario? I looked up some info and found that in the olden days there were library assemblies and process assemblies. Do we have a third type of "assembly" these days?
  2. I removed "dynamic" in the description of the "additionalDeps" scenario because we need to further explain what "dynamic" means. Dynamic in what sense? How is "dynamic" contrasted with the NuGet package and class lib scenarios ... are they "static" in some sense?
  3. Rick has suggested that this topic have a section listing all of the OOB hosting startups. I can find them across the various repos with an aspnet-wide search for "IHostingStartup." However if the list is short and you know it off the top of your head, can you provide the list? If not, no worries ... I'll search them out.

@guardrex guardrex changed the title [WIP] Hosting startup topic updates Hosting startup topic updates Jul 23, 2018
@guardrex guardrex removed the WIP label Jul 23, 2018
@guardrex
Copy link
Collaborator Author

@Tratcher I'm sure it needs more work, but take a 👀 now. There were a lot of updates this round.

<xref:fundamentals/host/hosted-services>
Learn how to implement background tasks with hosted services in ASP.NET Core.

<xref:fundamentals/configuration/platform-specific-configuration>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configuration/ -> host/

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rick-Anderson issued a ruling that UIDs are not allowed to change when topics are moved.

Learn how to implement background tasks with hosted services in ASP.NET Core.

<xref:fundamentals/configuration/platform-specific-configuration>
Discover how to enhance an ASP.NET Core app from a class library or external assembly using an `IHostingStartup` implementation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between a class library and an external assembly? You mean from assemblies your app may or may not reference? Change class library to referenced assembly and external assembly to unreferenced assembly?


To discover hosting startup assemblies loaded by the app or by libraries, enable logging and check the application logs. Errors that occur when loading assemblies are logged. Loaded hosting startup assemblies are logged at the Debug level, and all errors are logged.

## Disable automatic loading of hosting startup assemblies
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should ASPNETCORE_HOSTINGSTARTUPASSEMBLIES be discussed before Disable?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These sections originally ended up here due to your feedback at #4967 (review) ...

Let's move these new sections to the very top right after the opening paragraph, they are applicable to the most users. Comparatively few users implement this feature.

I'm not sure it matters. All it's really saying is list them in this env var and they go away. ASPNETCORE_HOSTINGSTARTUPASSEMBLIES isn't directly relevant to the goal of this section, is it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just though it was weird you said how to turn the feature off before you said how to turn it on.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I first added it, it was way down at the bottom just above the last section on the sample app.

76db1ec

If you want me to move the disabling part back down there, let me know. We can tack-on a sentence to the discovery section that says ...

To disable hosting startup enhancements, see <bookmark>.


Each approach is described in the following sections.

## NuGet package activation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nuget packages are not treated specially for this feature, they're only a mechanism for acquiring the class library dependency. This can be added as a note in the class library section, it doesn't need its own section.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are not treated specially for this feature

I understand that from the engineering perspective (i.e., delivery is a separate issue), but we're dealing with a slightly complicated scenario overall with some subtle differences between the gross implementation approaches (gross = including delivery).

It's easier to organize the topic content for clarity on the differences by going with separate (but similar) sections due the differences in procedure. This leaves the reader simply to ask, "How do I want to supply this?" Then, they read the applicable section. Otherwise if they aren't sure, they can read them in a more SxS fashion and easily compare and contrast the two.

If we roll NuGet into the class lib section (and remove the parts of the sample that pertain to the NuGet approach ... probably water down the text to basic 'use NuGet to deliver it' statements), I think the gross implementation will become harder to understand.

It's your call ... I'll cut it if you want, but I don't recommend it. If you want to proceed with cutting/moving, do you want it out of the sample, too?

Just remember as u make your final call, I didn't write this for you ... I wrote it for ME. 😄 lol

Copy link
Member

@Tratcher Tratcher Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you keep it then there are some parts that need to be fixed up. E.g. you say to set the environment variable to packageid, but the env var always needs to use the assembly name which may not match the packageid.


[!code-csharp[](platform-specific-configuration/samples/2.x/HostingStartupApp/Pages/Index.cshtml.cs?name=snippet1&highlight=7-8,13-14)]

The compiled class library is bin-deployed to the app, and the class library's assembly name is listed in the `ASPNETCORE_HOSTINGSTARTUPASSEMBLIES` environment variable. The environment variable is a semicolon-delimited list of assemblies that contain a `HostingStartup` attribute that identifies a hosting startup enhancement to load.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really matter where the binary is in this case, so long as the application has a compile time reference to it. E.g. it could be in the runtime store, in the bin directory, etc., so long as it's in one of the normal runtime search paths.


## Assembly activation

This section describes how to activate a hosting startup from a bin-deployed or runtime store-deployed assembly.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from an assembly that you do not have a compile time reference for. This is something a hosting provider like azure might provide.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will only work for .NET Core, not .NET Framework. The direct dependency approach works on both.


### Create the assembly

An `IHostingStartup` enhancement is deployed as an assembly based on a console app without an entry point. The assembly references the [Microsoft.AspNetCore.Hosting.Abstractions](https://www.nuget.org/packages/Microsoft.AspNetCore.Hosting.Abstractions/) package:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helps it generate the correct deps file (correct?).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the wrapper project and getting the right deps file came about from @pakrym's comment here 👉 #4438 (comment) (referring to answering me on 4 and 7).

What's the deal with the hosting startup on ...

  • Compile-time reference present: No deps file needed (no additional deps specification)
  • No compile-time reference: Deps file needed (additional deps specification required)

If you can help me understand that, I think a few words in the topic on it would help readers understand the requirement in the no-compile-time reference scenario.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core will only load assemblies listed in a deps file. When you have a compile time reference then the dependent assembly and all of its own dependencies end up in the app deps file. When you don't have a compile time reference then you need to provide a supplementary deps file with all of that assemblies dependencies.

Copy link
Collaborator Author

@guardrex guardrex Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under the class lib approach if the class lib's assembly is placed into the runtime store, is an explicit compile-time reference required in the consuming app's project file?

I have it bin-deployed in the text and sample app with a reference in the sample app's project file ..

<ItemGroup>
  <Reference Include=".\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll">
    <HintPath>.\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll</HintPath>
    <SpecificVersion>False</SpecificVersion> 
  </Reference>
</ItemGroup>

I'm just wondering in the runtime store case what the compile-time reference looks like. We may need to add it. [EDIT] ... add it in-text ... not in the sample.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't require a compile time reference, just an additional deps. That's how we ended up using it for AppInsights and AppServices. Go look at C:\Program Files\dotnet\additionalDeps\Microsoft.AspNetCore.AzureAppServices.HostingStartup.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of overlapping parts between the scenarios. What if we start by explaining the smaller components and then pull them together in the two main scenarios at the end? And those scenarios build on eachother. E.g. the no-compile-time-reference scenario is an expansion on top of the compile time reference scenario that uses all the same mechanics and adds the additional deps.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that sounds good (devil might be in the details tho). I'll take a good night sleep + up early + plenty of ☕️ and see how it goes in the morning.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to know this tho -------

What's the practical difference between:

  • A class lib in the runtime store with additional deps
  • A console app without an entry point in the runtime store with addtional deps

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

@guardrex guardrex Jul 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently if the console app w/o entry point assembly is bin-deployed with a compile-time ref, there's no need to deal with the deps file (just like in the console lib assembly case).

Assembly type (delivery options)

  • Class lib in a local assembly (runtime store, bin, or NuGet)
  • Console app w/o entry point (runtime store, bin, or NuGet - can it be packed?)

Delivery options

  • runtime store without compile-time ref and provide deps
  • bin with compile-time ref
  • NuGet package with compile-time ref

Outline

🥁 roll plz ...

[This outline is in the order of presentation.]

The pieces are just about all here, so I'm not sorry about the work that's been done thus far. However, let's settle on an outline (maybe that one ☝️) before I continue.

Posers, questions, queries

  1. What's the practical difference between class lib and console app w/o entry point approaches? Since it looks like they can both delivered with any delivery approach here, it comes down to the practical difference between them. Which one makes sense for given scenarios?
  2. Are class lib+NuGet package and console app w/o entry point+runtime store the most common anticipated assembly+delivery approaches? If so, the sample only needs to show these two.
  3. Between NuGet package on nuget.org and NuGet package in the runtime store, shall we just link out, or shall we link out with guidance on pros+cons?
  4. Can we say something about installer options? ... making delivery dead-on simple in multi-machine environments without using NuGet? ... or do we just lean in the direction of you should always use NuGet!

@guardrex guardrex changed the title Hosting startup topic updates [WIP] Hosting startup topic updates Jul 28, 2018
@guardrex guardrex added the WIP label Jul 28, 2018
@guardrex guardrex mentioned this pull request Jul 28, 2018
32 tasks
@Tratcher
Copy link
Member

Something about the organization is still bugging me. The ordering seems strange and ASPNETCORE_HOSTINGSTARTUPASSEMBLIES is duplicated several times. If I'm trying to author one of these what progression would I need?

How's this for a TOC?

  • Intro to IHostingStartup
  • HostingStartup attribute
  • Activation via ASPNETCORE_PREVENTHOSTINGSTARTUP
  • Disable automatic loading
  • Discover loaded hosting startup assemblies
  • Referencing the assembly
    • Overview: Core vs Framework, deps, gac, etc..
    • Project dependency, class library, bin deployed
    • Nuget dependency, class library, bin deployed
    • Runtime store, class library
      • Deps generation, DOTNET_ADDITIONAL_DEPS

@guardrex
Copy link
Collaborator Author

I didn't do the outline work that I show in #7678 (comment). I'll take another look at what I have there and what you posted and see what the differences are.

Check my Activation node in that outline tho ... I have the env var moved up very early. However, I do have creating the class lib or console app w/o entry point before that.

Before I do anything tho, I probably need to hear the answers to these questions ...

  1. What's the practical difference between class lib and console app w/o entry point approaches? Since it looks like they can both delivered with any delivery approach here, it comes down to the practical difference between them. Which one makes sense for given scenarios?
  2. Are class lib+NuGet package and console app w/o entry point+runtime store the most common anticipated assembly+delivery approaches? If so, the sample only needs to show these two.
  3. Between NuGet package on nuget.org and NuGet package in the runtime store, shall we just link out, or shall we link out with guidance on pros+cons?
  4. Can we say something about installer options? ... making delivery dead-on simple in multi-machine environments without using NuGet? ... or do we just lean in the direction of you should always use NuGet!

cc: @pakrym

@guardrex
Copy link
Collaborator Author

guardrex commented Jul 30, 2018

I looked this over in comparison ...

  • Intro to IHostingStartup
  • HostingStartup attribute
  • Activation via ASPNETCORE_PREVENTHOSTINGSTARTUP
  • Disable automatic loading
  • Discover loaded hosting startup assemblies
  • Referencing the assembly
    • Overview: Core vs Framework, deps, gac, etc..
    • Project dependency, class library, bin deployed
    • Nuget dependency, class library, bin deployed
    • Runtime store, class library
      • Deps generation, DOTNET_ADDITIONAL_DEPS

I didn't include a complete outline before, so a couple of those would've been left in-place.

  • Your outline doesn't show creating the assembly (especially in relation to "referencing" or "activating" it).
  • Idk on the deltas between "Core vs Framework" or additional content on "deps" and "gac" ... Thus far, I'm just trying to doc what's there today for Core. If bits are missing, I need more guidance.
  • You have "disable" and "discover" in the middle ... between activation and referencing, but I think those two either need to go first or last.
  • Sequence: Not sure how to interpret "activation" then "referencing." These could be interpreted as the same thing. By "referencing" the assembly, one is also "activating" it at runtime.
  • As for your 'Referencing the assembly' part, that matches what I have (but in a different sequence).

Broadly speaking, my outline does this ...

  • Create assembly
  • Reference/activate assembly

Breaking down Create, it's either ...

  • Class lib
  • Console app w/o entry point

(I need to hear more on the scenarios where they apply in the real world so I know what to tell readers.)

Breaking down Activation, it's ...

  • List in the env var
  • Placement/deployment/delivery: Specific instructions depending on delivery choice (in order of best/most common to worst/least common):
    • Runtime store
    • NuGet
    • bin deployment

Therefore, I devised it this way (and I'll add those discovery/disable bits this time) ...

... but even if that's a good work starting point, I need the answers to those posers that I listed earlier ☝️ before I proceed.

@Tratcher
Copy link
Member

Tratcher commented Aug 1, 2018

I've asked @pakrym for a second opinion on organization and to answer some of your technical questions.

@guardrex guardrex changed the title [WIP] Hosting startup topic updates Hosting startup topic updates Aug 1, 2018
@guardrex guardrex removed the WIP label Aug 1, 2018
@guardrex
Copy link
Collaborator Author

guardrex commented Aug 2, 2018

@Tratcher Gave it a pass this morning. It seems fine to me ... I didn't get 😵 outside of the questions I asked earlier. I ended up moving the section on the attribute to the top of the topic, but I left the "discovery" and "disable" sections immediately under it. I left the sample code as it was until I receive more feedback.

[EDIT] btw -- If it makes sense to do so, this is a good time to change the file name (URL). The "platform-specific-configuration" segment might be better as "hosting-startup." I can't change the UID, but we can change this aspect.

@pakrym
Copy link
Contributor

pakrym commented Aug 2, 2018

I distinguish Activation from a class library from Activation from an assembly (the "additionalDeps" scenario). I don't think it's clear/correct in its present form. I guess a console app without an entry point is an "assembly." What do we call the "assembly" (console app without an entry point) that's activating the hosting startup in the "additonalDeps" scenario? I looked up some info and found that in the olden days there were library assemblies and process assemblies. Do we have a third type of "assembly" these days?

I think there is a bit of confusion about why exactly we have a class library and console app. Let me clarify a bit.

What usually happens when we build hosting startups is first we create an implementation library (the one the has IHostingStartup) and target appropriate TFM in it (netstandard/netcoreapp) and treat it as a normal package.

Problem with a class library is that we can't get additional deps file out of it (because deps files are runable application assets) and you can't generate runtime store for it either (dotnet store needs a runable project that targets shared runtime to generate store). That's where console application comes into play, we create a dummy app that references our hosting startup package and targets some shared runtime [1] and then publish it to get additional deps file (nice consequence of having an app is that all shared framework stuff is trimmed from deps file automatically). We also call dotnet store on the same app project and get runtime store generated.

The last thing we need to do is to remove dummy app entry from .deps.json file because we won't be shipping it and runtime would fail to start if it's not found.

[1] - shared runtime you target should be the same as the framework name you put into additionalDeps subdirectory.

I removed "dynamic" in the description of the "additionalDeps" scenario because we need to further explain what "dynamic" means. Dynamic in what sense? How is "dynamic" contrasted with the NuGet package and class lib scenarios ... are they "static" in some sense?

Dynamic here means that you expand application dependency closure in runtime dynamically vs build time (at build time you do it by referencing packages).

Rick has suggested that this topic have a section listing all of the OOB hosting startups. I can find them across the various repos with an aspnet-wide search for "IHostingStartup." However if the list is short and you know it off the top of your head, can you provide the list? If not, no worries ... I'll search them out.

Two largest ones are:

  1. https://github.com/aspnet/AzureIntegration/tree/master/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup for AppServices integration

  2. ApplicationInsights - it's source is not public

@guardrex
Copy link
Collaborator Author

guardrex commented Aug 2, 2018

@pakrym Thanks for explaining. Yes, you were correct to clarify the dynamic approach. I can enhance the topic's dynamic content with the information you provided.

You don't address the static (compile-time referencing) approach for a class lib/NuGet package.

I'm attempting to follow @davidfowl's guidance in his remark on the issue at #6896 (comment) (repeated here) ...

This document describes how to use IHostingStartup in a completely dynamic way but fails to describe the HostingStartup assembly attribute that can point to types in existing referenced libraries. https://github.com/aspnet/Hosting/blob/8377d226f1e6e1a97dabdb6769a845eeccc829ed/samples/SampleStartups/StartupInjection.cs#L8

We should talk to about the IHostingStartup feature, what it does and then describe the various ways to consume it starting from the very simple attribute to the dynamic additional deps way.

Focusing on ...

assembly attribute that can point to types in existing referenced libraries

... and ...

describe the various ways to consume it starting from the very simple attribute to the dynamic additional deps way

Do the approaches on this PR meet those goals?

RE: The practical diff between static and dynamic ...

It looks like the practical diff is just that ... The dynamic approach doesn't require the compile-time ref. The static approach does. That's it (it seems). If so, that's easy enough to remark upon in the topic.

For the sample updates on this PR (to match the approaches described in the topic), I have:

  • A compile-time ref to a class lib.
  • A compile-time ref to a NuGet package.
  • The dynamic, no-compile-time ref console app approach.

Is that good?

@guardrex
Copy link
Collaborator Author

guardrex commented Aug 4, 2018

Latest version is creating additional questions/concerns ...

  1. If the runtime store delivery is only associated with the dynamic approach (console app w/o entry point), then this outline is splitting this content in an unnatural way. My first outline/original commit didn't have this split, so it might be better to revert. I'll paste a new draft outline below for discussion.
  2. @pakrym The explanation you gave (dynamic approach) doesn't mirror the instructions that we provided in the topic when the topic was first written. Either there's something wrong with the instructions/approach in the topic, the cheese has moved, or the framework is performing some steps and the developer is performing other steps and they're commingled. For example ...
    1. There's not obviously an implementation library (ordinary package reference) with the dynamic approach shown in the topic ... IHostingStartup impl is just a class in the console app.
    2. "We" create a dummy app? Who is "we"? ... the dev or the framework? Isn't the console app here created by the developer? It doesn't make sense to me right now given the steps that I currently have that there's another console app involved in the process.
    3. dotnet store isn't being used with the sample demo in the topic. The process is manual. The deps file is modified manually (by a PS script in the demo). The compiled assembly and deps files are manually placed (via MSBuild target in the demo). The assembly is placed in the runtime store when the dev (target in this case) moves it, so idk if you're saying the framework calls dotnet store later ... at activation ??? ... or has the cheese moved on the entire approach here since the topic was first written?

If the original topic (and my current instructions are incorrect), I should've pinged you back in December. #4967 However, @davidfowl didn't say in his issue that there was anything cosmically wrong with how the dynamic approach is explained in the topic today. He seems to want the class lib (bin or NuGet delivery) approach explained via a compile-time reference. #6896

Hypothetical outline reversion to recombine runtime package store delivery with the dynamic approach:

  • Introduction
  • HostingStartup attribute
  • Discover hosting startups
  • Disable automatic loading of hosting startups
    • All
    • Specific assemblies
  • Approaches summary
    • Compile-time reference to assembly
    • Dynamic approach w/o compile-time reference to assembly
  • Compile-time reference to assembly
    • Class lib
    • Compile-time reference activation
      • NuGet
      • bin
  • Dynamic approach w/o compile-time reference to assembly
    • Console app w/o entry point
    • Runtime store activation
      • Where to place assembly and deps file
      • deps file reference in env var
  • List in ASPNETCORE_HOSTINGSTARTUPASSEMBLIES (applies to all approaches and activation strategies)
  • Sample app

@pakrym
Copy link
Contributor

pakrym commented Aug 6, 2018

>There's not obviously an implementation library (ordinary package reference) with the dynamic approach shown in the topic ... IHostingStartup impl is just a class in the console app.

Depends on the requirement. If the only requirement is to produce output that would work with additionalDeps/runtime store having IHostingStartup in console app is enough. Sometimes having HostingStartup Nuget package is required and aconsole app would produce an unusable package. So having package and app covers all the scenarios.

"Who is "we"?

The dev. Everything I talked about was from the point of view of HostingStartup package author.

dotnet store isn't being used with the sample demo in the topic.

dotnet store is required if hosting startup has more dependencies then just the shared framework because they have to be collected too. It would also put hosting startup dll itself into the correct folder structure.

so idk if you're saying the framework calls dotnet store later ... at activation ??? ... or has the cheese moved on the entire approach here since the topic was first written?

No, dev has to call dotnet store somewhere in the build pipeline. dotnet store when ran on a .csproj collects it's dependencies and places them into a correct folder structure that later can be dropped into runtime store location.

@scottaddie scottaddie closed this Aug 9, 2018
@scottaddie scottaddie reopened this Aug 9, 2018
@guardrex guardrex force-pushed the guardrex/hosting-startup-updates branch from 412c2cd to 5c7aaa4 Compare August 19, 2018 13:42
@guardrex
Copy link
Collaborator Author

guardrex commented Aug 20, 2018

@pakrym U cool with the latest updates?

I produce a deployment folder with ...

  • An assembly folder containing the assembly.
  • An additonalDeps folder containing the modified deps file.
  • A PS script that adds or updates the env vars for the demo StartupDiagnostics assembly.

@Rick-Anderson
Copy link
Contributor

@pakrym Can you review the last and hopefully final updates?

@pakrym
Copy link
Contributor

pakrym commented Aug 27, 2018

Looks good. Awesome work @guardrex !

@guardrex
Copy link
Collaborator Author

guardrex commented Aug 27, 2018

Thanks @pakrym ... that means a lot to me coming from you.

@guardrex guardrex closed this Aug 27, 2018
@guardrex guardrex reopened this Aug 27, 2018
@guardrex guardrex requested a review from scottaddie August 28, 2018 01:49
@@ -4,7 +4,7 @@ author: guardrex
description: Learn about the ASP.NET Core Web Host and .NET Generic Host, which are responsible for app startup and lifetime management.
ms.author: riande
ms.custom: mvc
ms.date: 05/16/2018
ms.date: 07/27/2018
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

07 --> 08

Learn how to implement background tasks with hosted services in ASP.NET Core.

<xref:fundamentals/configuration/platform-specific-configuration>
Discover how to enhance an ASP.NET Core app from a referenced or unreferenced assembly using an `IHostingStartup` implementation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Remove the extra space after "referenced".
  • Link to the IHostingStartup API ref

To disable automatic loading of hosting startup assemblies, use one of the following approaches:

* To prevent all hosting startup assemblies from loading, set one of the following to `true` or `1`:
- [Prevent Hosting Startup](xref:fundamentals/host/web-host#prevent-hosting-startup) host configuration setting.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convert dashes to asterisks


1. An implementation library is created from the class that contains the `IHostingStartup` implementation. The implementation library is treated as a normal package.
1. A console app without an entry point references the implementation library package. A console app is used because:
- A dependencies file is a runnable app asset, so a library can't furnish a dependencies file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use asterisks instead of dashes

This command places the hosting startup assembly and other dependencies that aren't part of the shared framework in the user profile's runtime store at:

```
<DRIVE>\Users\<USER>\.dotnet\store\x64\<TARGET_FRAMEWORK_MONIKER>\<ENHANCEMENT_ASSEMBLY_NAME>\<ENHANCEMENT_VERSION>\lib\<TARGET_FRAMEWORK_MONIKER>\
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path looks specific to Windows. What about macOS and Linux?

If you desire to place the assembly and dependencies for global use, add the `-o|--output` switch to the `dotnet store` command with the following path:

```
<DRIVE>\Program Files\dotnet\store\x64\<TARGET_FRAMEWORK_MONIKER>\<ENHANCEMENT_ASSEMBLY_NAME>\<ENHANCEMENT_VERSION>\lib\<TARGET_FRAMEWORK_MONIKER>\
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is Windows specific again. I recommend using OS tabs.

The [sample code](https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/host/platform-specific-configuration/samples/) ([how to download](xref:tutorials/index#how-to-download-a-sample)) demonstrates three hosting startup implementation scenarios:

* Two hosting startup assemblies (class libraries) set a pair of in-memory configuration key-value pairs each:
- NuGet package (*HostingStartupPackage*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convert dashes to asterisks

</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.2" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgrade to 2.1.3

nuget.org.
-->
<PropertyGroup>
<RestoreSources>$(RestoreSources);https://api.nuget.org/v3/index.json;../HostingStartupPackage/bin/Debug</RestoreSources>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this typically defined in a NuGet.config file? What's the advantage of putting it here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how typical it is. It works either way. I like this approach because it applies the sources only to the current project. I think everyone has had the unfortunate experience where a Nuget.config messes up the SDK or the sources for some downstream project. If they want that, it's great. When they don't and it isn't clear where the config is coming from, it's very frustrating. I don't think that would be a problem here, but this approach is supported.

@dasMulli ... Do you have any thoughts on the two approaches? From your research, do you think MS has pushed devs toward one approach over the other?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things here:

  1. pointing to a bin/Debug output as restore source is a bit hacky but I don't know the context here. (what if it fails, what if NuGet decides that you haven't changed any feeds/references and does a no-op (incremental) restore etc.)

  2. There's also RestoreAdditionalProjectSources for project-specific sources. But now idea how well a "manage package for solution" dialog works for this.

The property-based approach is nice if you don't want to explain NuGet.config and the mechanism behind and it is easy to set in Directory.Build.props for all projects, even for local paths by using $(MSBuildThisFileDirectory)local\nupkgs from it. Also, you can make use of standard MSBuild conditions to alter the restore sources which is why dotnet/aspnet moved to them to be able to use different sources for different types of builds which would require editing NuGet.config for every build otherwise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dasMulli

True ... it's a bit of a hack. It has the following benefits/goals in this context:

  1. It allows the dev to create and use the HostingStartupPackage NuGet package in the HostingStartupApp by just building that HostingStartupPackage NuGet package project and then building/running the HostingStartupApp.
  2. They don't need to move anything (i.e., they don't need to move the NuGet package out of the HostingStartupPackage project). They don't need to take any additional steps in HostingStartupApp to find and consume the package.
  3. They don't need to put the package on nuget.org. That's the really important goal here.

you haven't changed any feeds/references and does a no-op (incremental) restore

I thought that if the NuGet package is rebuilt that NuGet will pick up on that (without a package version change). Does NuGet go purely by the package's version on incremental restore? That is a problem if that's the case. I would like to have this set up so that the dev can make a change to the NuGet package project and have it picked up on restore/run of the HostingStartupApp.

RestoreAdditionalProjectSources

Can the additional project source be a NuGet package that is then consumed by the app? If I can use RestoreAdditionalProjectSources pointed to the NuGet package project, that would be great ... but is that going to work for consuming a NuGet package? If so, do I then drop the <RestoreSources> property?

Copy link

@dasMulli dasMulli Aug 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guardrex AFAIK you'd have to do a dotnet nuget locals all --clear if you change package contents without changing the version anyway - regardless of which feed the package is coming from (directory, web feed).
That's why you should always use project (P2P) references during development or use a local "global packages cache" to nuke in between full rebuilds (CI runs).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a project reference?

Copy link
Collaborator Author

@guardrex guardrex Aug 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a project reference?

Because the app consuming a hosting startup should not have a project reference (for this particular scenario ... for the 'consume it from a package scenario') ... it should have an actual NuGet package reference to demo this. That's the way the app would actually consume the hosting startup.

Therefore, I wouldn't mind it if a project reference did produce a real NuGet package. It sounds like you're saying tho that it won't do that and that the consuming app wouldn't also have a regular package reference, too.

Therefore, I think I just need to remind readers that if they change the package project and recompile it that they'll also need to execute a cache clearing as you say to make sure that the project that consumes the package will get a fresh copy from the package project.

As for the <RestoreSources> versus Nuget.config situation, I still feel like this should stick with <RestoreSources>. It's simpler this way, and it's well documented in the consuming project's project file. I doubt that devs getting geared up to use a hosting startup will have any problem with this approach.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dasMulli ... I pushed a commit to make sure devs know that if they change the package project to clear caches. That looks good.

I'm going to leave the <RestoreSources> in the app as is. Unless @pakrym says 'don't do that,' it seems like a very clean, easy-to-use, easy-to-grok setup for the demo. I'm just trying to show how the hosting startup consumer takes a real package, and I don't want the dev to have to put a hosting startup package on nuget.org or need to sweat a Nuget.config file with the source (which I think buries how the source is being set).

Your advice on the caches should go well 👍. They just need to do that each time they make changes to the hosting startup package. 🤞

37562f0

</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.1.2" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgrade to 2.1.3

@guardrex
Copy link
Collaborator Author

@scottaddie @pakrym These look correct based on my iMac research.

For the user profile versions ...

/Users/<USER>/.dotnet/store/x64/...

For the machine-wide versions ...

/usr/local/share/dotnet/store/x64/...

I also updated the Windows ones to use env vars ...

%USERPROFILE%\.dotnet\store\x64\...
%PROGRAMFILES%\dotnet\store\x64\...

@guardrex
Copy link
Collaborator Author

@scottaddie Unless there's anything else, I think we're in good shape here. The paths for Mac/Linux seem good based on my iMac research here at the house. I'm sure the community will come for my head 🔪 👦 if I made a boo boo, but my iMac is saying these are good. (We'll blame my iMac if they're wrong. 🙈)

@guardrex
Copy link
Collaborator Author

Thanks again to @dasMulli! 🚀 🚀 🚀 ... the tip for clearing local caches is critical for the dev who wants to play with the NuGet package approach and get their hosting startup package updated in the app. That was a 🎸 rockstar suggestion 🎷.


### Console app without an entry point

*This approach is only available for .NET Core apps, not .NET 4.x.*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.NET 4.x.* --> .NET Framework


* [Runtime store](#runtime-store) &ndash; Activation doesn't require a compile-time reference for activation. The sample app places the hosting startup assembly and dependencies files into a folder, *deployment*, to facilitate deployment of the hosting startup in a multimachine environment. The *deployment* folder also includes a PowerShell script that creates or modifies environment variables on the deployment system to enable the hosting startup.
* Compile-time reference required for activation
- [NuGet package](#nuget-package)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use asterisks here instead of dashes?


## Activation

Three options for hosting startup activation are:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see 2 options listed here.


---

If you desire to place the assembly and dependencies for global use, add the `-o|--output` switch to the `dotnet store` command with the following path:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switch --> option


The location of the implementation's *\*.deps.json* file is listed in the `DOTNET_ADDITIONAL_DEPS` environment variable.

If the file is placed in the user profile's *.dotnet* folder for per-user use, set the environment variable's value to:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "for per-user use". That's implied when you reference "user profile" earlier in the sentence.


---

For the sample app (*HostingStartupApp*) to find the dependencies file (*HostingStartupApp.runtimeconfig.json*), the dependencies file is placed in the user's profile. and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and


For more information on NuGet packages and the runtime store, see the following topics:

* [How to Create a NuGet Package with Cross Platform Tools](https://docs.microsoft.com/dotnet/core/deploying/creating-nuget-packages)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the "https://docs.microsoft.com" prefix from these 3 links.


## Sample code

The [sample code](https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/host/platform-specific-configuration/samples/) ([how to download](xref:tutorials/index#how-to-download-a-sample)) demonstrates three hosting startup implementation scenarios:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should "three" be "two"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to the problem you pointed about above: There are ... for lack of a better expression ... three options that call under two approaches. ei ei ei. I think the word "three" can be removed to solve it most easily.


**Activation from a runtime store-deployed assembly**

1. The *StartupDiagnostics* project uses [PowerShell](/powershell/scripting/powershell-scripting) to modify its *StartupDiagnostics.deps.json* file. PowerShell is installed by default on Windows OS starting with Windows 7 SP1 and Windows Server 2008 R2 SP1. To obtain PowerShell on other platforms, see [Installing Windows PowerShell](/powershell/scripting/setup/installing-windows-powershell).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • OS
  • I suspect you want to link here instead in that last sentence: /powershell/scripting/setup/installing-powershell#powershell-core

```console
dotnet store --manifest StartupDiagnostics.csproj --runtime win7-x64
```
For Windows, the command uses the `win7-x64` runtime identifier (RID). When providing the hosting startup for a different runtime, substitute the correct RID.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link the RID text to the following doc: /dotnet/core/rid-catalog

For Windows, the command uses the `win7-x64` runtime identifier (RID). When providing the hosting startup for a different runtime, substitute the correct RID.
1. Set the environment variables:
* Add the assembly name of *StartupDiagnostics* to the `ASPNETCORE_HOSTINGSTARTUPASSEMBLIES` environment variable.
* On Windows, set the `DOTNET_ADDITIONAL_DEPS` environment variable to `%UserProfile%\.dotnet\x64\additionalDeps\StartupDiagnostics\`. On macOS/Linux, set the `DOTNET_ADDITIONAL_DEPS` environment variable to `/Users/<USER>/.dotnet/x64/additionalDeps/StartupDiagnostics/`, where `<USER>` is the user profile that contains the hosting startup.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to introduce OS tabs here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed the command by showing <RID>. Therefore, there's only one sentence left specific to non-Windows ... this one. Let's see on the next commit. It might not be worth it to copy the entire set of steps into three tabs only to accommodate the single sentence.

from the app's bin folder.
-->
<ItemGroup>
<Reference Include=".\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dasMulli,
It does seem hacky to hardcode certain pieces of this path. Should they be converted to variables? For example:

  • Debug --> $(Configuration)
  • netcoreapp2.1 --> $(TargetFramework)
  • HostingStartupLibrary.dll --> $(AssemblyName)

Copy link
Collaborator Author

@guardrex guardrex Aug 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a great idea. We do that elsewhere, and we probably should do it here, too.

I'll use different names. They refer to characteristics of another project (e.g., the hosting startup package project, the hosting startup lib). I'll make it clear in their names on the next commit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk on this now ....... this is taking something very simple and making it very messy. It takes three vars for both to define them. It makes it harder to see what it is .... just a path. I'd rather be super clear on the components of the path than have a bunch of vars stuck in here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So.. one is a package reference and the other a Reference instead of a project-to-project reference..

I'd argue that the Reference should really be a ProjectReference instead, so it is built, up-to-date and you get the correct path.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw i'd prefer <Reference Include="path/to/some.dll" /> instead of the hint path approach.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that @scottaddie ... I just noticed that you are correct about the instructions and location for the hosting startup library. The instructions are correct ... I didn't recall that I have the dev deploy the assembly to the consuming project. These scenarios aren't exactly easy to track. I'll add project file language to reinforce the concept, and I'll add the vars you recommended.

☕️ ....... one more cup please!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug --> $(Configuration)
netcoreapp2.1 --> $(TargetFramework)
HostingStartupLibrary.dll --> $(AssemblyName)

All of these only apply when the referenced project is built under the exact same parameters.

  • $(Configuration) -> Probably okay if they are built in the same solution and users didn't mess with solution configurations.
  • $(TargetFramework) -> as long as the library isn't a netstandard*...
  • $(AssemblyName) -> only if the referenced project's .csproj file has the exact same name as the currently built project.. don't think that will happen

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these only apply when the referenced project is built under the exact same parameters.

It's just for the path tho (within the consuming project; I mean the configuration and the target framework vars), so the path to the DLL should be correct.

I need to think this over a little more. Everything we've discussed has merit, but this is on a slippery slope to being so ✨ magical ✨ that it clouds the basic concepts.

Copy link

@dasMulli dasMulli Aug 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's also..

<ProjectReference Include="../some/other.csproj" 
       ReferenceOutputAssembly="false" />

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fleshing out some details in the app's project file to explain what's going on.

I may also mirror some or all of the new remarks in the topic itself.

It will be on the next commit.

@guardrex guardrex added the WIP label Aug 31, 2018
@guardrex
Copy link
Collaborator Author

guardrex commented Aug 31, 2018

Ok ... here's what I came up with.

I provide additional notes to hopefully make it clear what's going on in the project file.

I don't want those notes in the topic. These are sample demo implementation details. They're a bit beyond the scope of the hosting startup basic concepts. The topic states plainly what the options are and links out where needed (e.g., NuGet packages).

I add a couple of lines where the deployment options are described explaining the circumstances where the two main compile-time approaches apply. In the first case, it would be a NuGet package published to nuget.org. In the lib case, it would be a compiled assembly moved to some location where an app can take a compile-time ref on its assembly.

Let's deal with any confusion that arises in the community as we get feedback. I'm sure they'll let me know if things turn sour.

@guardrex guardrex removed the WIP label Aug 31, 2018
@guardrex guardrex merged commit defd561 into master Aug 31, 2018
@guardrex guardrex deleted the guardrex/hosting-startup-updates branch August 31, 2018 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants