-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Add AppContext.ApplicationName #15618
Comments
@davidfowl is this for display purposes or will there be decisions based upon it? If it is settable is it safe to assume it should fail if someone sets it more than once? |
@weshaggard not for display. Decisions will be made based on this for sure.
I'm not sure it needs to be that strict. You could imagine a layered system that composes different entry points. Each of those entry points changes the name based on arguments passed into it. It shouldn't throw. |
Can you point me at code where you use it to make decisions? It seems like it would be trouble if decisions are made and someone changes it and now different decisions are made. |
I think it is fine to overwrite the value as long as no-one has read it. Once it is read it should be fixed to make sure all the decisions are made based on the same value. |
I wonder how much usage this would get? My gut reaction is that it is a bit of a niche API, at least the way it's being described (global user-controlled string that is settable/resettable). I think if I wanted to use an API like this, I would either:
I'm not really able to follow the example you linked closely, but that's probably because I'm not familiar with this area of ASP.NET. It seems like it's mainly being used as a fallback to a user-configurable string value, where the value has to be equal to the assembly name anyways (just going by the name of the variable "StartupAssemblyName"). Is there a use case in a more simplified context? It's hard to judge whether it would be useful in a general sense with an example that's so closely tied to a specific ASP.NET context. |
Don't think of it as ASP.NET. Here's another scenario. Lets say I did some assembly loading based on the application name, by default it's the app entry point. Now say that I'm writing a functional/unit test and I want to change that context when running form a unit test since the unit test binary is the host. |
Maybe of ApplicationName should be an |
I think AssemblyName is more confusing than ApplicationName but it depends on what you actually end up storing in there. Can you give an example of the value this will hold? Regardless of the name, my plan is to allow users to set the value as many times as they want until a read of the value happens. After that. Calls to set will throw. @davidfowl let me know if that covers your scenario. |
@AlexGhiondea, can you drive this through the API review? It seems there are still some pending concerns around:
|
@terrajobst - absolutely! |
Reason for APIEntryAssemblyIdentityThere are certain scenarios where the assembly that CLR considers as the 'EntryAssembly' is not the assembly the application considers as the 'EntryAssembly'. Here are two examples where the host considers the 'EntryAssembly different than what the CLR does:
Proposed APInamespace System
{
public static partial class AppContext
{
public static string EntryAssemblyIdentity { get { return default(string); } set { } }
}
} DetailsEntryAssemblyBy default (if the host does not overwrites it) this API will return the value of the 'EntryAssembly' from the CLR's perspective (which, if you are a host, will be the assembly for the host). However, managed hosts are able to change this value to something else, depending on their requirements. The semantics of this API allow setting it multiple times until the value is read once. This ensures that the value has a consistent value once it was read. Assembly identityThe 'identity' of the assembly is defined as the FullyQualified name of the Assembly (including name, culture and public key) as a string. The string returned from this property should be parseable by the constructor for 'AssemblyName'. We chose to expose this information via a string in order to maintain the dependencies of AppContext to a minimum. Having this API return an AssemblyName would require a dependency to System.Reflection which we would like to avoid. |
I dunno, would anyone actually want to do this? It seems to me like a stretch to call that the "Entry Assembly", considering how many other assemblies are typically entered before it in a typical testing framework. It feels like this would just be using the property as a "convenient global string".
I'm a bit concerned about the usability of this. For example, if a library wanted to use this value, it would have to make it clear to the application that it needed to set the EntryAssemblyIdentity before calling any of the functions in the library. Also, it would be very weird if you were writing some code, tried to set the EntryAssemblyIdentity, and got an exception because one of the libraries you called had already read the value (without telling you). It's a pretty bad experience, I think. The Command Line parsing library we use (for GenFacades and others) could potentially use this property (right now it just uses Assembly.GetEntryAssembly). If it wanted to do so, applications would need to set the value before calling CommandLine.Parse, or not set it at all. It would be up to the library author to make it really obvious how that would work, which would end up being very confusing, I think (because people wouldn't document it). Also, going back to the unit testing use case. If you can only set it once, how will that work for test runners that let you run multiple test assemblies? For example, xunit.console lets you pass multiple test assemblies into the runner, and it will run them one at a time. This wouldn't really work there, because you could only set the property once for the first test assembly. |
Thanks @mellinoe for you comment! Those are some great points. I think I heard two major areas for feedback. Let me try and address them: Unit testing
That is the point. If there are multiple assemblies loaded, the order in which they are loaded would be irrelevant. The host would be responsible for setting the value of the property to the assembly that contains the code to be tested. I guess there is nothing that prevents the host from writting anything it wants in the field which would essentially turn it into a global string.
Indeed. However, the purpose of this property is to be set by the host and be read by the application. Once the host has correctly setup the AppDomain it should transfer control to the hosted application which would then be able to read the value. I don't expect that we would want libraries to set this value. One way to think about this is similar to the 'EntryAssembly' property on AppDomain. That property is read-only and it is set at application startup by the runtime. That value cannot be changed by the application.
This is interesting. Do you know if xunit will create a new AppDomain for each of the assemblies it has to test? If so, then for each AppDomain it uses it can correctly set this property corresponding to the tested assembly. Allowing this to be changed at any time is somewhat problematic. If the value is not consistent across application calls, the application would get different values depending on when it reads the value. Usability of the API
The idea is that by the time the application has started running, this value is set to its final value and there should be no reason for the application to try and set it. I did consider an approach where this scenario would be supported: namespace System
{
public static partial class AppContext
{
public static string EntryAssemblyIdentity { get { return default(string); } }
public static bool TrySetEntryAssemblyIdentity(string entryAssemblyIdentity) { return default(bool); }
}
} If we think the current approach is too hard to figure out then we can remove the setter and add the above method. |
Ah, I think there's a bit of a misunderstanding / miscommunication. Is the EntryAssemblyIdentity settable by the application, or just by the runtime host? Your proposal has this: public static string EntryAssemblyIndentity { get { return default(string); } set { } } Which led me to believe that the application could call the set accessor as many times as it wanted before the get acessor was called. I'm also confused by the second iteration, which still has a TrySet method. If it is set-in-stone by the time the application is running, why is there any concept of setting it in the API? That does clear things up a bit, but I still have the same general issues with it. It's still unclear how a testing framework would use it, especially if it's not actually settable within an application. xunit.console is just a runtime-agnostic .NET executable, it has no concept of a runtime host, so it therefore can't take any dependency on such a runtime concept. For example, if xunit wanted to use this now, you'd have to make sure you hosted the CLR with some special, magic string set somewhere, otherwise you wouldn't discover any tests, or get some weird error.
Well, for our CoreCLR tests, everything is just in the same AppDomain, as far as I am aware. I don't think we spawn multiple processes to isolate tests (since we can't create new AppDomain's on .NET Core). I'd have to double check the runner code about that, though. So this would sort of prevent the API from being usable for that purpose, at least with the current xunit runner. |
Only for unit tests which directly and only target the desktop CLR (meaning, the |
I don't think we should focus on unit testing as the main scenario. Here are some other ones:
Those are the sorts of scenarios where the host process can set the real entry point. |
I agree on that. We (xUnit.net) currently have no intention of using this API. |
There have been a couple of questions about what this API would be useful. Please correct me if I am wrong but so far, the only scenario where this property would be helpful is in the cases where your application is a hosted application. I think this covers all the scenarios @davidfowl mentioned (asp.net, service host, cloud service). That is a valid scenario. What I am trying to understand is what are the use cases for this property so that we can figure out the best shape of this property/API. Here are a couple of questions to try and gather some more data:
|
I've run across this in one place, in the xunit runner for DNX:
It looks like it was being used to figure out the name of the entry assembly. Since we're planning to add GetEntryAssembly, it seems this scenario would be resolved. One scenario where this property or one like it would be very useful is in help content generation for Command Line apps. One typically wants to display something like:
This sort of help content can be generated by libraries intended to parse the cmd line. It is very inconvenient to tell the libraries what the application is called explicitly since this can change over time and there is no tools support for "refactoring" an output assembly's name across code. It would be very convenient, then, to have the ability to determine the name of the application at runtime, across renames. |
What would you expect the EntryAssembly to be in this case? Would it not be "MkDir" ? The command-line parser for our internal tools just uses the name of the EntryAssembly for this purpose, although I can perhaps imagine some times where you'd want something different. If you want the "Application Name" to be something different, how would you envision it is set, changed, etc.? Is it settable at runtime, re-settable? Or is it static, based on a manifest, an assembly attribute, something else? |
If this "Application Name" can be arbitrarily set, how is it in any way meaningful? You only end up in a "who got there first (or last) to change it" scenario. Some other code from a 3rd party host or library could have already changed it to meet its needs without any regard for others just as the intended benefactor would. Adding rules to when it can and can not be set does not matter as its still depends who got there first. Why not just use an environment variable or If a developer can't trust your API calls, then they will not use them. An API should do what it says it will do not what arbitrary host/library authors decide it should do as a workaround for an issue. #DirtyHack |
@piotrpMSFT wrote:
I don't think so. Wouldn't the entry assembly in this case be |
Exactly! That was the whole reason for having that ApplicationName property... It's all about the hosting model... |
@bradwilson @davidfowl If you are not writing a managed host (like dnx), then GetEntryAssembly will indeed return the right value since the runtime will load and set the right assembly as the entry assembly. If you are writing a managed host then it is possible for the host to define a contract between itself and the apps that it is hosting and call out
To me it seems like the managed host scenario requires an explicit contract between what the host puts in the value and how the hosted app uses it. And each host/hosted app could choose to use different things. |
Is this still needed? If not, I will close the issue. |
closing, we added a custom api in asp.net |
There are cases where the exe name and the application are not the same. Consider a scenario where the entry point of the application is not user code, it could be a different host (like when you're running in windows service) that loads your application as a plugin (.dll). We do this today in ASP.NET and there are 2 modes of execution:
This name should be settable (and not only by the native host). This should default to the application with the entry point by default.
/cc @lodejard @nguerrera @joshfree @AlexGhiondea
The text was updated successfully, but these errors were encountered: