aspnet / Mvc

[Archived] ASP.NET Core MVC is a model view controller framework for building dynamic web sites with clean separation of concerns, including the merged MVC, Web API, and Web Pages w/ Razor. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
5.62k stars 2.14k forks source link

Compiling views from .net framework project #8623

Closed IncIouds closed 6 years ago

IncIouds commented 6 years ago

Is this a Bug or Feature request?:

Hmm, bug?

Steps to reproduce (preferably a link to a GitHub repo with a repro project):

Below

Description of the problem:

I have .net standard 2.0 library(sdk=Microsoft.NET.Sdk.Razor), called SelfHost. SelfHost starts kestrel web host server with MVC. SelfHost contains also controllers and views. Building produces SelfHost.Views.dll, controllers from SelfHost are loaded, everything till this point works fine. And the tricky part: i want SlefHost to also load controllers and views from client app(assembly that references this library). SelfHost detects controllers from another assembly using

services.AddApplicationPart(clientAssembly)

Detecting views from another assembly is realized by:

services.Configure<RazorViewEngineOptions>(options => options.FileProviders.Add(new EmbeddedFileProvider(clientAssembly));

In this approach, views build action from client project has to be set to "Embedded Resource"

Case 1: Running .net core console app(sdk=Microsoft.NET.Sdk) that uses SelfHost, without adding additional controllers and views to console app. So we have clean console app with controllers and views only from SelfHost. Result 1: Everything works fine. I have access to controllers, views are returned.

Case 2: Running .net core console app(sdk=Microsoft.NET.Sdk.Razor) that uses SelfHost, with adding additional controllers and views to console app. So we have console app with controllers/views from selfhost and controllers/views from console app. Result 2: Everything works fine. I have access to SelfHost and console app controllers. Views from SelfHost and console app are returned.

Case 3: Running .net core console app(sdk=Microsoft.NET.Sdk, without Razor) that uses SelfHost, with adding additional controllers and views to console app. So we have console app with controllers/views from selfhost and controllers/views from console app. Result 3: When trying to access view from console app i am getting:

One or more compilation references are missing. Ensure that your project is referencing 'Microsoft.NET.Sdk.Web' and the 'PreserveCompilationContext' property is not set to false. The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) [assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCore._Views_Jakis_Index), @"mvc.1.0.view", @"/Views/Jakis/Index.cshtml")] The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@"/Views/Jakis/Index.cshtml", typeof(AspNetCore._Views_Jakis_Index))] Predefined type 'System.Type' is not defined or imported [assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCore._Views_Jakis_Index), @"mvc.1.0.view", @"/Views/Jakis/Index.cshtml")] Predefined type 'System.String' is not defined or imported [assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCore._Views_Jakis_Index), @"mvc.1.0.view", @"/Views/Jakis/Index.cshtml")] Predefined type 'System.String' is not defined or imported [assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCore._Views_Jakis_Index), @"mvc.1.0.view", @"/Views/Jakis/Index.cshtml")] Predefined type 'System.String' is not defined or imported [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@"/Views/Jakis/Index.cshtml", typeof(AspNetCore._Views_Jakis_Index))] Predefined type 'System.Type' is not defined or imported [assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@"/Views/Jakis/Index.cshtml", typeof(AspNetCore._Views_Jakis_Index))] The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?) using System; The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?) using System.Collections.Generic; The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?) using System.Linq; The type or namespace name 'System' could not be found (are you missing a using directive or an assembly reference?) using System.Threading.Tasks; The type or namespace name 'Microsoft' could not be found (are you missing a using directive or an assembly reference?) using Microsoft.AspNetCore.Mvc; The type or namespace name 'Microsoft' could not be found (are you missing a using directive or an assembly reference?) using Microsoft.AspNetCore.Mvc.Rendering; The type or namespace name 'Microsoft' could not be found (are you missing a using directive or an assembly reference?) using Microsoft.AspNetCore.Mvc.ViewFeatures; The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"3884152d0999a8c1c979e05ec6b3e584997f3684", @"/Views/Jakis/Index.cshtml")] Predefined type 'System.String' is not defined or imported [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"3884152d0999a8c1c979e05ec6b3e584997f3684", @"/Views/Jakis/Index.cshtml")] Predefined type 'System.String' is not defined or imported [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"3884152d0999a8c1c979e05ec6b3e584997f3684", @"/Views/Jakis/Index.cshtml")] Predefined type 'System.String' is not defined or imported [global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"3884152d0999a8c1c979e05ec6b3e584997f3684", @"/Views/Jakis/Index.cshtml")] The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) public class _Views_Jakis_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference? public class _Views_Jakis_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage Predefined type 'System.Boolean' is not defined or imported public class _Views_Jakis_Index : global::Microsoft.AspNetCore.Mvc.Razor.RazorPage The return type of an async method must be void, Task or Task public async override global::System.Threading.Tasks.Task ExecuteAsync() The type or namespace name 'System' could not be found in the global namespace (are you missing an assembly reference?) public async override global::System.Threading.Tasks.Task ExecuteAsync() The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } Predefined type 'System.Void' is not defined or imported public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; } The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } Predefined type 'System.Void' is not defined or imported public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; } The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } Predefined type 'System.Void' is not defined or imported public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; } The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } Predefined type 'System.Void' is not defined or imported public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; } The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } Predefined type 'System.Object' is not defined or imported public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference? public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } Predefined type 'System.Boolean' is not defined or imported public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } Predefined type 'System.Void' is not defined or imported public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper Html { get; private set; } '_Views_Jakis_Index.ExecuteAsync()': no suitable method found to override public async override global::System.Threading.Tasks.Task ExecuteAsync() The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute] The type or namespace name 'Microsoft' could not be found in the global namespace (are you missing an assembly reference?) [global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]

This error also occurs when console app is on .net framework stack. I suppose this is because there is no available razor sdk to compile this views. Is there any solution to that problem? I would like to use this SelfHost library also in .net framework components, where i cannot set sdk to Microsoft.NET.Sdk.Razor.

Version of Microsoft.AspNetCore.Mvc or Microsoft.AspNetCore.App or Microsoft.AspNetCore.All:

2.1.3

pranavkm commented 6 years ago

Compiling views at runtime, which is what happens with views in an EmbeddedFileProvider, requires the compilation context to be set. Could you try setting <PreserveCompilationContext>true</PreserveCompilationContext> in your project and see if that helps here?

That said, I'm not entirely sure about this

I would like to use this SelfHost library also in .net framework components, where i cannot set sdk to Microsoft.NET.Sdk.Razor.

Why can't you reference the Sdk to Microsoft.NET.Sdk.Razor in your project, assuming you can target Microsoft.NET.Sdk?

IncIouds commented 6 years ago

Compiling views at runtime, which is what happens with views in an EmbeddedFileProvider, requires the compilation context to be set. Could you try setting <PreserveCompilationContext>true</PreserveCompilationContext> in your project and see if that helps here?

That said, I'm not entirely sure about this

I tried to set <PreserveCompilationContext>true</PreserveCompilationContext> in .csproj of .net framework 4.6.2, but it didn't work. I read somwhere on the internet that this flag is set to preserve .deps.json file, which contains all references. The problem is, there is no .deps.json file creating while building .net framework project.

I would like to use this SelfHost library also in .net framework components, where i cannot set sdk to Microsoft.NET.Sdk.Razor.

Why can't you reference the Sdk to Microsoft.NET.Sdk.Razor in your project, assuming you can target Microsoft.NET.Sdk?

I can target Microsoft.NET.Sdk or Microsoft.NET.Sdk.Razor in .net core/.net standard project, but what about .net framework? How to do that? Is that even possible?

I tried to load every assembly from my bin/debug folder of .net project application. This try is based on assumption that building .net framework project copies all dependency libraries to bin folder. So if i target .net standard lib(with target type set to .net framework), then in build process, i will end up with all dependent libraries(among others ones used to compile views for SelfHost), copied to my console app bin folder. Now i get the error message: Targeted tag name cannot be null or whitespace.

I tried also method of adding Metadata References from this topic https://github.com/dotnet/core-setup/issues/2981 (it was written by you @pranavkm, on 15 Aug 2017). The problem is, DependencyContext.Load returns null for every AssemblyPart in my .net framework console application. In .net core app it seems that DependencyContext.Load returns not null DependencyContext for every AssemblyParts, which contains multiple CompileLibraries. I read that DependencyContext.Load used .deps.json, so it would make sense that it is null for .net framework project, because it doesn't have one :(

pranavkm commented 6 years ago

I can target Microsoft.NET.Sdk or Microsoft.NET.Sdk.Razor in .net core/.net standard project, but what about .net framework? How to do that? Is that even possible?

You can target .NET Framework in a SDK-style project (for instance this project cross-compiles. Here's a minimal template for a project target net462:

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
    <TargetFramework>net462</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
  </ItemGroup>

</Project>

I'd start from here and see if you can get your application to run correctly.

IncIouds commented 6 years ago

I can target Microsoft.NET.Sdk or Microsoft.NET.Sdk.Razor in .net core/.net standard project, but what about .net framework? How to do that? Is that even possible?

You can target .NET Framework in a SDK-style project (for instance this project cross-compiles. Here's a minimal template for a project target net462:

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
    <TargetFramework>net462</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
  </ItemGroup>

</Project>

I'd start from here and see if you can get your application to run correctly.

You are not answering my question. Maybe i asked it wrongly. I have set target framwork of SelfHost package(.net standard) to net462 long time ago. Thats not the issue. I have .net framework 4.6.2 console app which relies on this package, and views defined in console app can't be compiled correctly in runtime. Maybe using Microsoft.NET.Sdk.Razor tools in console app(.net framework 4.6.2 project) would help?

pranavkm commented 6 years ago

Maybe using Microsoft.NET.Sdk.Razor tools in console app(.net framework 4.6.2 project) would help?

Yes. Alternatively putting the views in a class library that references the Razor Sdk would also work.

IncIouds commented 6 years ago

Maybe using Microsoft.NET.Sdk.Razor tools in console app(.net framework 4.6.2 project) would help?

Yes. Alternatively putting the views in a class library that references the Razor Sdk would also work.

Putting views in another library is not the option. How can i use Microsoft.NET.Sdk.Razor in .net framework project? What should i add to .csproj? I didn't find anything helpful on the internet on that matter.

pranavkm commented 6 years ago

What should i add to .csproj?

I listed the template for a desktop targeting Sdk project template here - https://github.com/aspnet/Mvc/issues/8623#issuecomment-432743858. I'd start from there.

IncIouds commented 6 years ago

What should i add to .csproj?

I listed the template for a desktop targeting Sdk project template here - #8623 (comment). I'd start from there.

It actually worked. Thank you very much!