Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running ASP.NET Core MVC as a Console Application Project without .NET Core SDK

Problem Background

I'm creating a tool, tha generates MVC solutions(*.sln) and building(with msbuild) them so they could be deployed. Tool requires .NET Framework 4.5.2.

Now I want to generate ASP.NET Core MVC application. Such applications could be run under 4.5.X, but I'm unsure if msbuild could handle project.json(so i'm using packages.config) and I cannot install .NET Core as every tutorial indicate as prerequisite for developing ASP.NET Core. Currently I'm planning to deploy generated applications on Windows.

The Problem:

So instead of .NET Core project I've created a simple console application: enter image description here There I've installed there all packages needed, like:

  <package id="Microsoft.AspNetCore.Mvc" version="1.0.1" targetFramework="net452" />

And SelfHosted the application using Kestrel:

    public class Program {
    static void Main() {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}

I've added Controller with a View. When I do a request, controller is hit, but View cannot be compiled in runtime: enter image description here

Is this behavior related to the fact I'm using Console Application and not ASP.NET Core Web Application? Is it possible to create a full-featured MVC application as a simple console application?

UPDATE:

I think I've found a workaround inspired from reading github issues:

 public void ConfigureServices(IServiceCollection services) {
        services.AddMvc()
                .AddRazorOptions(options => {
                                     var previous = options.CompilationCallback;
                                     options.CompilationCallback = context => {
                                                                       previous?.Invoke(context);
                                                                       var refs = AppDomain.CurrentDomain.GetAssemblies()
                                                                                           .Where(x => !x.IsDynamic)
                                                                                           .Select(x => MetadataReference.CreateFromFile(x.Location))
                                                                                           .ToList();
                                                                       context.Compilation = context.Compilation.AddReferences(refs);
                                                                   };
                                 });
    }

That seems to make Razor to render my view. But I'm not sure yet if it can be accepted as a solution.

like image 598
3615 Avatar asked Oct 19 '16 10:10

3615


Video Answer


1 Answers

Right now, it's not possible to build a .NET Core app using MSBuild, but it's possible to create a console application (not .NET Core) and add the same packages using NuGet (step-by-step below).

According to this road map, it will be possible in the near future.

Info from the link above:

Q4 2016 / Q1 2017

This will be the first minor update, mainly focused on replacing .xproj/project.json with .csproj/MSBuild. Project format update should be automatic. Just opening a 1.0 project will update it to the new project format. There will also be new functionality and improvements in the runtime and libraries.*

EDIT (steps to create a console app with Kestrel):

I created a Console application (not .NET Core console) and I was able to run Kestrel with a simple MVC API.

Here's what I did:

  • I saw the dependencies I use in an existing .NET Core app, then, I added them as a NuGet reference:

    "Microsoft.AspNetCore.Mvc": "1.0.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
    
  • Modified the main method:

    static void Main(string[] args) {
      var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();
      host.Run();
    }
    
  • Created a Startup.cs (UPDATED with the workaround provided in the question):

    public class Startup {
      public Startup(IHostingEnvironment env) {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
      }
    
      private IHostingEnvironment CurrentEnvironment { get; set; }
      private IConfigurationRoot Configuration { get; }
    
      public void ConfigureServices(IServiceCollection services) {
              services.AddMvc().AddRazorOptions(options => {
               var previous = options.CompilationCallback;
               options.CompilationCallback = context => {
                 previous?.Invoke(context);
                 var refs = AppDomain.CurrentDomain.GetAssemblies()
                        .Where(x => !x.IsDynamic)
                        .Select(x => MetadataReference.CreateFromFile(x.Location))
                        .ToList();
               context.Compilation = context.Compilation.AddReferences(refs);
              };
            });
      }
    
      public void Configure(IApplicationBuilder app) {
        app.UseStaticFiles();
    
        app.UseMvc(routes => {
          routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
        });
      }
    }
    
  • Add a class to be my MVC Controller:

    [Route("api/[controller]")]
    public class ValuesController : Controller {
    
      // GET api/values
      [HttpGet]
      public IEnumerable<string> Get() {
        return new string[] { "value1", "value2" };
      }
    
  • I had to copy manually the libuv.dll file to the bin folder because I was getting an error.

With these steps, I was able to run my console application. In the image below, you can see my project structure and Kestrel running:

enter image description here

like image 154
Fabricio Koch Avatar answered Sep 18 '22 11:09

Fabricio Koch