2

I have a project that targets .NET Standard 1.5 that is deployed as several DLLs on NuGet. The project was ported from Java. Inside some of the classes of the project are static Main() methods that are meant to be run from the command line.

In .NET Core it seems there are 2 ways to compile a DLL:

  • <OutputType>Exe</OutputType> - compiles into an executable console app (DLL)
  • <OutputType>Library</OutputType> (default) - compiles into a class library (DLL)

What I am wondering is there a way to compile the DLL so it can be used either way without having 2 separate (confusing) DLLs?

Basically, I am trying to get similar functionality to that in Java where a package can be referenced by an application or run on the command line (and to specify the entry target on the command line).

Example

For example, in Java there are files that are both part of the package and contain a static Main(object[] args) method.

public class SomeClass
{
    public void DoSomething(string arg1, string arg2, string arg3)
    {
        // implementation...
    }

    public static void Main(object[] args)
    {
         // parse args...

         new SomeClass().DoSomething(arg1, arg2, arg3);
    }
}

DoSomething is referenced elsewhere within the package (which is equivalent to what my NuGet packages look like now). However, in Java the Main(object[] args) can be run from the command line like...

java <package>.jar <namespace>.SomeClass [args]

without having to download or install anything extra. After all, if the component the user wants to run the command on is there, all of the dependencies are there, too.

Ideally, I can just use similar functionality in dotnet core...

dotnet <assembly>.dll <namespace>.SomeClass [args]

which would be preferable to having to create a separate wrapper DLL around the whole thing, or make a separate project that has to pick and choose all of the dependencies of SomeClass so they are all compiled into a single assembly (console app).

Furthermore, there are several static Main() methods per package, which seems to have been supported in .NET Core earlier which is what my other question is about.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • 1
    Why not encapsulate the logic into a NuGet package and then consume that from a console application? – mason Jun 29 '17 at 16:41
  • Seems like a pain for the users. It would be far preferable to have a single binary package per platform so you can just drop it into a folder and run the CLI command than to have a whole mess of dependencies. I am looking into [ILLink](https://github.com/mono/linker) (similar to ILMerge for .NET Core) to solve that issue. – NightOwl888 Jun 29 '17 at 17:06
  • 1
    Are you distributing your executable application via NuGet? That's not what NuGet is for. – mason Jun 29 '17 at 17:08
  • No, I am not. I am distributing DLLs for use in applications. But in Java, these same packages could be run from the CLI and I am trying to work out if that is an option here rather than having to package up a separate binary that they would need to download separately. In the latter case, it would be best to ILLink them, but that is not my preference. – NightOwl888 Jun 29 '17 at 17:16
  • If you're simply distributing DLL's for use in applications, then do it via NuGet. I really don't understand what the problem you're trying to solve is. – mason Jun 29 '17 at 17:19
  • @mason - I added an example to my question. – NightOwl888 Jun 29 '17 at 17:36
  • I don't get why you'd want to do that. Libraries are meant to be consumed by applications. Even if you can directly execute them, that's silly. It shows a bad separation of concerns. Put your logic in a NuGet package, then consume it from an executable. – mason Jun 29 '17 at 17:38
  • I want to do that because if I have to create a *separate binary* that has to be downloaded from a different source than NuGet, it won't be as easy to find or use as the original app this is based on. Why not simply give the users the command line option for free simply by installing DLL rather than making it a whole bunch of research to run the *exact same* functionality from the command line as you would have by taking the time to make build a custom app to run it? – NightOwl888 Jun 29 '17 at 17:46
  • Because it shows poor separation of concerns, and NuGet is used to distribute libraries, not executable programs. Create a library, put it in NuGet, deliver the functionality via normal methods for distributing an executable program such as the Windows Store or Chocolatey or putting it on your website. Don't abuse things. You think you're making it easier but you're actually making things up when you abuse them. – mason Jun 29 '17 at 17:49
  • Right - but I am not as concerned with separation of concerns as I am with making this *a lot like* the application I am porting (which apparently didn't take that into consideration). – NightOwl888 Jun 29 '17 at 17:51
  • If you're creating a .NET application, follow .NET paradigms. Don't bring over Java paradigms because .NET developers don't care about Java's paradigms. – mason Jun 29 '17 at 17:53
  • Originally, I started out this pursuit with the intent of creating a wrapper application with separate commands (one for each `Main()` method), but since I discovered that [dotnet CLI is very similar to Java](https://stackoverflow.com/a/39155842/181087), I decided to pursue that approach first to see if it makes sense. Adding several hundred more lines to maintain just to run this *already existing* functionality in a more complicated way seems like an inferior approach, not to mention the users can already download and run the Java CLI so I am not gaining much by adding a .NET alternative. – NightOwl888 Jun 29 '17 at 18:09

2 Answers2

3

With .Net Standard/Core, your best option is to have a second project that compiles to an EXE who has a simple Main() method that points to the library's version. It isn't ideal, but the issue is how the runtime for .Net core works. A project that targets .Net Standard can be used by all projects compatible with that standard version. A project that targets a specific .NetCoreApp can only be referenced by other .NetCoreApps, so you don't get the benefit of targeting the standard.

For the packaging/NuGet deployment, the console app version can be put into the tools folder of the NuGet so an end user can use it. You don't really want executables to be deployed via the standard NuGet content folder because it won't really follow the standard and be confusing for your NuGet users.

Michael Weinand
  • 401
  • 2
  • 4
  • Thanks for bringing up the issue with .NET Standard/.NET Core. I wonder if that will affect the ability to merge using [ILLink](https://github.com/mono/linker)..? – NightOwl888 Jun 29 '17 at 17:09
  • But unless I am willing to [make the tradeoff](https://learn.microsoft.com/en-us/dotnet/core/deploying/index) to make self-contained deployment, it won't be an EXE file as you said. Although, that may ultimately be the way to go if I can't figure out a way make multi-purpose DLLs that "just work" without having to download an extra console app. – NightOwl888 Jun 29 '17 at 17:12
  • See this thread: https://github.com/dotnet/corefx/issues/11672 - I think one of your issues is that you would have to do it for each platform. I think your link to self-contained deployments is probably your best bet. – Michael Weinand Jun 29 '17 at 17:15
0

You get it for free with .Net EXE (which is just an assembly the same way as DLL and can be referenced as such).

To get close with DLL you'd need to make .Net DLL usable in some way from command line. Exposing some native-compatible entry point and using rundll32 to access it from command line is an option to achieve that - Need to run a c# dll from the command line.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • That seems to only apply to .NET Framework. I would prefer to target .NET Core so I can get cross-platform support for free. – NightOwl888 Jun 29 '17 at 17:07