dotnet / project-system

The .NET Project System for Visual Studio
MIT License
969 stars 387 forks source link

Add support for ASP.NET (non-Core) projects #2670

Open NickCraver opened 7 years ago

NickCraver commented 7 years ago

We routinely run into cases where the new project system and ASP.NET MVC 5 collide (or rather, don't) - I'd like to see support added. Here are the main use cases I'm aware of, I hope others add more to this issue:

Use Case: Migration

One of the awesome features of the new .csproj system is glob patterns (and Visual Studio not replacing them on every save). This was something we really looked forward to as a real time saver and merge reducer, but in practice we can't use the new project system because a lot of functionality for ASP.NET MVC 5 apps is missing, e.g. even hitting F5 to run it.

When we migrate a large solution to ASP.NET Core, it's a stop-the-world endeavor as are most major changes. Swapping any fundamental framework piece will need to be a big swap, so you want to reduce that window and risk as much as possible. In the case of ASP.NET to ASP.NET Core, you need to swap the project file, all references, port controllers, views, etc. This is a lot to do at once, and every change since you started that path is a royal pain.

A large part of this pain is in the project file itself, since nearly every commit adding or removing files is a merge conflict. And when moving from non-glob to blog worlds, it's a huge pain to manually sync everything into that major change branch.

But why not just stay on non-globs until after the move?

Again, merge pain. A large change like this necessitates moving files around quite a bit and that's the same merge pain between users as exists in 1 world today.

Use Case: Library Projects

We also have several projects that need to support ASP.NET and ASP.NET Core, there are hundreds of thousands of users on the old systems and we need to support them. In the ASP.NET cases specically, we need to have a ASP.NET and an ASP.NET Core sample. In all of these, the only use of the old project system is the ASP.NET (non-core) sample projects. We have to choose between:

Adding support for ASP.NET MVC 5 projects for example would help tremendously in porting to ASP.NET Core. In our case, it'd help now for library projects (needed dependencies for main websites to move), and later for those sites like Stack Overflow. We've been working on the .NET Core story for quite a while now, but the daunting task of upgrading the main applications would be made much easier if we could get on the new project system first.

For today examples, I'm using the new .csproj in MiniProfiler and Exceptional MVC 5 Sample projects. The upside is management and simplicity, the downside is users constantly asking why F5 doesn't work. At the moment I'm considering changing them to the old system since the main point of a sample is a bit missed when they can't test it.

Use Case: Immediate

Additionally, it'd just make life easier today in itself, apart from upgrade reasons, by:

Can we please consider adding support for these project types? Such support would make life easier both immediately and for upgrading in the future.

davkean commented 5 years ago

yet ASP.NET (non-Core) (e.g. this issue) isn't even tagged as a parity legacy issue.

My bad, tagged it.

Understand the disappointment, but at the end of the day like all software projects, we need to prioritize what we're going to focus on. For the first few updates of VS 2019, given we're on the hot path for .NET Core 3.0, we'll be focusing on WPF/WinForms. I've already investigated legacy Razor support, and it is non-trivial given our integration with Roslyn is very different to the legacy project system.

If folks want to split out feature support into separate issues that would make ASP.NET/MVC dev easier on top of the new project system, I'm happy to take at look at each feature in isolation and maybe we can take contributions or sneak them in between our current priorities, but at the moment it's not clear in mind what exactly "ASP.NET support" means in terms of actual features without doing a deep dive into it.

wanton7 commented 5 years ago

This also very annoying for our company. We have all other projects in new csproj format. Biggest problem is that Razor can't see any changes in other project until you compile them and we have all our models in project that is in new csproj format. Plus if you hit F12 in Razor it goes to metadata and not to actual source code in other project. Not to forget lot of time you get errors in error window and in editor from Razor views about missing assemblies, but those Razor views work just fine.

NickCraver commented 5 years ago

Biggest problem is that Razor can't see any changes in other project until you compile them and we have all our models in project that is in new csproj format. Plus if you hit F12 in Razor it goes to metadata and not to actual source code in other project.

Yes. This is insanely annoying. It makes it look like a half-finished feature. It's not seamless, it's incredibly annoying, and it will cost us a lot of debug time. We're about to move all the Stack Overflow models out to another project in order to make the ASP.NET project as small as possible for an ASP.NET Core move later. But our options are: A) deal with what design-time things are broken builds and the inability to navigate source between the two. Or B) just ignore than the new project system exists.

We'll have to choose B so that the other devs don't murder me in the migration process. But this also means we can't multi-target and ensure we're even netcoreapp or netstandard compatible along the way, which is the entire point of moving this code ahead of time. I'm incredibly frustrated to see this indefinitely punted.

davkean commented 5 years ago

We're tracking this via https://github.com/dotnet/project-system/issues/3010, this is something I can see us tackling sooner rather than later. Can you make sure that bug captures all the issues you are running into around this?

bergmeister commented 5 years ago

@davkean I have to add one more issue to add to this: I can manually migrate an ASP.Net project to Packagereference and it works and VS shows the packages in References of the Solution Explorer but when using Manage Nuget Packages on the project or solution, the packages are not visible, which makes it impossible to use because then we cannot consistently update all our projects (which wouldn't be an issue if there was a built-in way to central manage packages in a solution that also works with the UI). I am using the latest released VS version 15.9.3

Pilchie commented 5 years ago

when using Manage Nuget Packages on the project or solution, the packages are not visible

@rrelyea - any ideas about this?

@bergmeister - I'd suggest a new item on https://github.com/NuGet/Home for this.

chucker commented 5 years ago

Isn’t that exactly the reason the packages.config migration UI doesn’t show up on ASP.NET projects?

bergmeister commented 5 years ago

@chucker No, the migration UI is only disabled because all generic cases are not covered yet, however there are still plenty of cases where one can migrate due to the features of the ASP.NET project being used (in this case an Angular project)

fredericDelaporte commented 5 years ago

I also wish the support of non core Asp.Net projects as a SDK project format, mainly for the sake of using globs. For my case, what I am lacking most when attempting to use the new format is full Intellisense support in dynamically compiled files. Yes, I mean those things under App_Code folder, or aspx/aspx.cs included as content with the .cs referred through CodeFile attribute instead of CodeBehind. Although supposed to be used with the old "web site" project (no project file), they are also supported in web application projects (old project file). But with SDK projects, even with @YakhontovYaroslav solution, there is no auto-completion available in dynamically compiled files excepted for things defined in the same file or, for aspx/ascx/master files, in their matching .cs.

I do not really expect this very old feature to be supported by the IDE with the new csproj format. But having instead globs available for the old format would be very welcome.

(By the way, using Microsoft.NET.Sdk.Web SDK is worst than Microsoft.NET.Sdk when your project also contains .asp files (yes, Classic Asp...): with the former, their contents do not show up anymore with the "HTML (Web Forms) Editor".)

304NotModified commented 5 years ago

FYI,

currently this issue has 188 votes, the 2nd has 24 votes...

304NotModified commented 5 years ago

Originally posted by @davkean in https://github.com/dotnet/project-system/issues/2670#issuecomment-444840632:

If folks want to split out feature support into separate issues that would make ASP.NET/MVC dev easier on top of the new project system, I'm happy to take at look at each feature in isolation and maybe we can take contributions or sneak them in between our current priorities, but at the moment it's not clear in mind what exactly "ASP.NET support" means in terms of actual features without doing a deep dive into it.

--> https://github.com/dotnet/project-system/issues/4557

IanKemp commented 5 years ago

@304NotModified Aaand it's Closed. :(

davkean commented 5 years ago

@304NotModified To update the thread. Our priorities have not changed, we are still focused on client scenarios for .NET Core 3.0 with the new project system for the first lot of updates for VS 2019. We will continue to make performance improvements to the legacy project system, but we will not port big new features to it. We did an investigation this time last year for globbing in particular, and it is significant cost that does not help in the direction of replacing it.

For some good news, we've fixed Razor "Go to definition" breaks when target is defined an SDK-style project in VS 2019 Preview 4, which improves the interopolitity between the two. Please tell us if you hit more issues like this.

@fredericDelaporte Can you file an issue on the IntelliSense code behind? Let's treat that as a separate issue. @bergmeister Did you file a bug against NuGet on that package reference issue? I've been unable to repro this.

kelps commented 5 years ago

Ok, here is another example: at our company we have a solution composed of several projects. One is the UI, a web forms application (for legacy and extensibility reasons at our clients, we can't go full MVC just yet).

Since each project has a very specific concern, we planned to have each house their own server controls and embed any necessary user controls (.ascx). We'll be using the virtual file provider in ASP.NET to get the embeded user controls.

Problem is, like @fredericDelaporte mentioned, with SDK style projects, I can't make the intellisense and code behind files (*.ascx.designer.cs) work at all. It works just fine if I try the exact same thing in a regular class library. Here are my steps:

If I do this in a regular class library, the code completion works just fine in the ascx file and the .designer file is generated and updated as expected. If I do this exact same steps in the SDK style class library (targeting the same .net framework), neither the code completions in the ascx nor the code behind work.

I even tried to edit the file to create and add the subtype to the files in the same way the regular project does, but it didn't work either.

Is there any way, even if somewhat manual, to make this file types work? Maybe register the custom tool manually? Or is this really something that the VS does and we can't really make it work at all?

Having a simplified file project is amazing and we really don't wish to go back if we can avoid. So much better not to have unnecessary merge conflicts.

weitzhandler commented 5 years ago

Hi guys, I have an old deployed ASP.NET project, that I need to start taking care of. All we have is the wwwroot folder. What we need to do is to recreate a VS project so we can debug it.

How can I recreate a new project from an old deployed wwwroot folder?

Thanks a lot!

maxinfet commented 5 years ago

@davkean In regards to this comment

If folks want to split out feature support into separate issues that would make ASP.NET/MVC dev easier on top of the new project system, I'm happy to take at look at each feature in isolation and maybe we can take contributions or sneak them in between our current priorities, but at the moment it's not clear in mind what exactly "ASP.NET support" means in terms of actual features without doing a deep dive into it.

I would be willing to go through the default templates and put them on the new project system and see what features I am aware of work and don't work. Is this typically how someone on your team would do this investigation or do you have sources that would give a better idea of what features you are looking for to see if they work?

mpawelski commented 4 years ago

Hi @NickCraver would you mind sharing your current experience with using ASP.NET MVC project that reference projects in new "sdk style .csproj" (.NET standard class libraries and .NET 4.8 framework class libraries). Is IDE experience still that horrible? Reading this thread made me very afraid to approach this rough migration plan for my team:

(My solution contains many projects. One ASP.NET 5 MVC project and lots of .net 4.8 class library projects)

  1. Move all .NET framework class libraries project to new sdk style csproj format
  2. Move most .NET Framework class libraries project to .NET Standard project
  3. Keep working in this state for possibly long time :(
  4. Keep refactoring and moving all existing .NET Framework class libraries to .NET Standard class libraries.
  5. Move one ASP.NET MVC 5 project to ASP.NET Core project

I'm afraid that while we are at 3. point developers will suffer because of number of IDE issues. But maybe since #3010 is fixed it is not an issue anymore?

I'm asking it here in public because I guess there are a lot of people like me that wonder this question and are discouraged to start migration after reading this thread.

seangwright commented 4 years ago

@mpawelski We have migrated all internal libraries to SDK style projects, whether those libraries target netstandard2.0 or netcoreapp3.0 (unit test projects for netstandard2.0 libs) or net472 (libs that support classic ASP.NET).

Our ASP.NET projects still use the old project system, but have migrated to using <PackageReference> for NuGet packages.

We've done this across many libraries and many projects and while occasionally there are issues we have to deal with (old NuGet packages that want to add/delete files, ps1 files) the costs are well worth the better developer ergonomics.

These migrations also prepare us for moving to ASP.NET Core for our ASP.NET apps and allow us to share libraries (with fewer issues) between ASP.NET Core and ASP.NET projects.

We've been doing this since 2017 and the dev experience has only gotten better since then.

Kralizek commented 4 years ago

@seangwright how about Razor in ASP.NET (non Core) applications? We had issues before (can't remember exactly what it was, it was a year ago)

IanKemp commented 4 years ago

@seangwright how about Razor in ASP.NET (non Core) applications? We had issues before (can't remember exactly what it was, it was a year ago)

Then... why not try it again, and actually post the issues you have, and maybe then we can assist?

NickCraver commented 4 years ago

@mpawelski We did 1-4 here, and indeed that combination of things (an ASP.NET MVC 5 old-.csproj on top of other SDK .csproj projects) works well today. I do not recommend trying to run ASP.NET MVC 5 as an SDK project, there's just too many things that are broken (especially Razor) and don't behave as developers expect. While I did this as an exercise to see what the gaps where, I'd never subject other developers and teams to it.

Overall, I recommend only moving to an SDK .csproj for a web project as you're moving to ASP.NET Core itself. We've about wrapped up the move for Stack Overflow and will be blogging a lot about it in the upcoming weeks and months in hopes that it helps others with their migrations.

seangwright commented 4 years ago

@Kralizek Like I said, using <PackageReference> with ASP.NET full framework projects is 👍👍 but like @NickCraver states, changing those ASP.NET full framework projects to SDK style projects is 👎👎.

This is why we haven't changed to SDK projects for the web application part of our solutions.

mpawelski commented 4 years ago

@NickCraver @seangwright Thank you guys for such reassuring answers! :)

Our ASP.NET projects still use the old project system, but have migrated to using <PackageReference> for NuGet packages.

@seangwright Wait, what? You mean inside .csproj (which is not new SDK style .csproj) you use <PackageReference> instead of generated <Reference Include="..."> <HintPath>...</HintPath> </Reference>?

Thanks, I didn't even knew it's supported! After quick search I see it's even documented. Other people also confirms it but recommend to stay with packages.config.

We've done this across many libraries and many projects and while occasionally there are issues we have to deal with (old NuGet packages that want to add/delete files, ps1 files) the costs are well worth the better developer ergonomics.

Besides this occasional problem does it mean that VS tooling like installing packages with Install-Package in Package Manager Console or using NuGet Package Manager ui works fine? Does installing packages that still adds binding redirects when necessary?

seangwright commented 4 years ago

1) Yes, we don't use <Reference Include=""> - there are numerous pain points with the old package resolution using that syntax - mainly related to transitive dependencies that don't resolve correctly. So, in our non-SDK .csproj files for the ASP.NET full framework projects we use <PackageReference> elements.

2) VS Tooling works just fine using the new <PackageReference> syntax. You can use the UI in VS, the NuGet powershell commands, or the dotnet cli to install or restore packages. Actually, the dev experience is even better in my opinion (the project "References" node differentiates between packages and assemblies/projects")

You can configure your Visual Studio instance to default to packages.config or <PackageReference> for new projects and you can also convert projects from the old version to the new one within Visual Studio.

However, Visual Studio doesn't support this conversion for ASP.NET project types (based on the project Guid).

There are a few ways around this (I've personally done all of them): 1) you can temporarily change the project Guid to something like the class library Guid, run the migration, and then change back 2) use an extension like https://github.com/CloudNimble/PackageReferenceUpgrader (only supported in VS2017) 3) migrate manually by deleting all <Reference> elements in the .csproj and installing packages until your project builds (🤷‍♂️).

Your packages.config file is not going to be a good source for indicating which packages need installed because it has always listed transitive dependencies along with direct dependencies - you will inevitably end up with fewer <PackageReferece> elements than original packages.config entries.

dazbradbury commented 4 years ago

Overall, I recommend only moving to an SDK .csproj for a web project as you're moving to ASP.NET Core itself. We've about wrapped up the move for Stack Overflow and will be blogging a lot about it in the upcoming weeks and months in hopes that it helps others with their migrations.

@NickCraver Any chance those blog posts are ready/public? If so would you mind linking to them? Our journey from MVC5 -> .Net Core could do with some guidance and our team would really appreciate it!

pnstickne commented 4 years ago

When updating to for a MVC "Web" Project to use Package References, there is a good chance that one also needs to 'cleverly' extract content from packages like Angular or Bootstrap. This is possible using PackageReferences and old-style projects.

It would be even easier if SDK-projects supported MVC. I don't understand why there is so much push back .. 3+ years of bickering of if something "should" be supported instead of just making a good transition.

tompazourek commented 4 years ago

I have an ASP.NET MVC 5 app that is converted to an SDK-style project (not just using PackageReference style restore, but the proper <Project Sdk="Microsoft.NET.Sdk">) and the main problem I experience is Razor Intellisense.

If folks want to split out feature support into separate issues that would make ASP.NET/MVC dev easier on top of the new project system, I'm happy to take at look at each feature in isolation and maybe we can take contributions or sneak them in between our current priorities, but at the moment it's not clear in mind what exactly "ASP.NET support" means in terms of actual features without doing a deep dive into it.

@davkean Would the MVC 5 Razor Intellisense be something that you'd be happy to take a look at if it was in a separate issue?

IanKemp commented 4 years ago

I don't understand why there is so much push back .. 3+ years of bickering of if something "should" be supported instead of just making a good transition.

There isn't pushback, there's simply the fact that the team is not going to implement this support. They aren't allowed to say that directly, but considering that the writing has been on the wall for everything Framework-related since .NET 5.0 was announced, we should all take the hint.

ASP.NET MVC apps are currently on life support, additional tooling for them at this point would be extending that life support so that companies can continue to justify putting off upgrading to Core. And that helps nobody, because ASP.NET MVC apps are universally terrible monsters suffused with tentacles of jQuery. It's time to let them die.

seangwright commented 4 years ago

Having adopted, several years ago, <ProjectReference> and SDK style projects in all the places they are supported with .NET 4.x, I can say it's been great that this backwards compatibility exists between .NET Core things and .NET Framework 4.x.

It has made our migration to .NET Standard, .NET Core, and soon .NET 5 much easier.

That said, I'm ok that ASP.NET apps on .NET 4.x don't support SDK style projects - <PackageReference> working is good enough to bridge the gap.

SDK style projects + ASP.NET is a feature that is reserved for .NET Core / .NET 5. Not every feature is backported, and the teams that support all this tech have to use their limited time and resources wisely.

.NET 5+ is going to continue to march forward, getting new features and tooling. We can't have our cake (.NET 4.x) and eat it too (.NET Core/.NET 5+ features).

At the same time, our .NET 4.x code is not going to stop working, I don't agree that it's on 'life support'. It still makes money for many businesses and developers using it can still be productive.

I think it's more important to get our ASP.NET apps on .NET 4.x into ship shape so that our dependencies on System.Web are abstracted away.

SDK style projects are a convenience, teams have been building apps for years with messy .csproj files (and doing it successfully!) - the lack of HttpContext.Current is going to be much more of a hurdle for many teams.

mpawelski commented 4 years ago

This issue is the most commented and most upvoted here so I'm sure the team is aware how much people want this. If I uderstand correctly it was at least investigated in the past and concluded it's not trivial to do.

Well, recently the team posted that there are planning what to do next for project system. Don't know what came out of it, but I guess we should not have high hopes regarding this issue...

On the bright side, I've been working on my old .NET 4.8 solution with all projects (class libraries, EF with migrations, console apps) migrated to new SDK-csproj, except one ASP.NET MVC 5 project which is old csproj but with new <PackageReference> nuget format and it's been a pleasure to work with. Much less changes in .csprojs for non web projects (resulting in less clutted PRs and merge conflicts) and the new nuget is much better to work with.

davkean commented 4 years ago

Hi folks,

We haven't forgotten about this item. It's currently our highest voted issue in this repository, and for good reason! When I started this project back in 2016, the initial aim for the new project system was to completely replace the legacy project system and all the individual project types. Over the past two majors releases we've taken a few detours from this to focus on supporting .NET Core 1.1/2.0, Windows Forms, WPF in .NET Core 3.0 and then finally .NET 5.0. After .NET 5.0, you'll start to see Xamarin and UWP/WinUI scenarios light up.

ASP.NET was always going to be some significant work. Unlike the other project types which have thin layers over the "base" legacy project system, there's significant infrastructure behind the scenes to make Razor/ASPX IntelliSense work in code that's as old as my 16-year old. There's also significant debugging differences, plus a bunch of scaffolding and long tail of other features.

In saying all this, however, I do bring some good news. This sprint, @BillHiebert and myself are working on a spike to investigate the feasibility of bringing up ASP.NET on the new project system. Note this isn't a promise to enable this support, this spike is solely to 1) figure out significant technical challenges, 2) figure out costs. After which, we'll bring back to management to make decisions on if/when we'll end up enabling this support.

@tompazourek Do you mind sharing a project containing your SDK-based MVC project? IntelliSense is the first thing I'm going to bite off, so would be good test case.

tompazourek commented 4 years ago

@davkean Thanks, that's great news. I'm happy to help so here you go: https://github.com/tompazourek/AspNetMvcOnSdk

EDIT: Just found out that my sample project above doesn't have these Intellisense issues in Rider. So it looks like Rider might be the way to go for ASP.NET MVC working on SDK-style projects (you'd still need a custom web publish script to copy just the right files for deployment purposes, a custom MvcBuildViews target if you use that, and you'd have to debug by attaching to the w3wp.exe process instead of using the Run button, but those aren't big obstacles).

jmezach commented 4 years ago

Honestly I would be okay with it only working for Web API projects. We have a whole bunch of them and would like to bring them forward without having to go to .NET Core immediately. Having the ability to use the new project system with our existing projects significantly improves developer experience and also makes the gap to Core smaller.

kemsky commented 4 years ago

Using several tricks from this thread I was able to convert ASP.NET MVC 5 app to the new project format, unfortunately, Rider can not run the app, it does not recognize RunCommand tag. Visual Studio debugging works just fine. Maybe somebody found a workaround for this?

This is a minimal working solution: https://github.com/kemsky/asp.net-mvc5-new-project-format


Updated sample with Rider debug information.

dazbradbury commented 3 years ago

In saying all this, however, I do bring some good news. This sprint, @BillHiebert and myself are working on a spike to investigate the feasibility of bringing up ASP.NET on the new project system. Note this isn't a promise to enable this support, this spike is solely to 1) figure out significant technical challenges, 2) figure out costs. After which, we'll bring back to management to make decisions on if/when we'll end up enabling this support.

@davkean - Thanks again for picking this up! Just wondering how the initial feasibility study went?

bachratyg commented 3 years ago

Adding these to the project seems to enable proper F5 debugging with launchSettings.json (generates .vs\...\applicationHost.config, uses ssl settings/launch url, launches browser, etc):

  <ProjectCapability Include="DotNetCoreWeb" />
  <ProjectCapability Include="SupportsSystemWeb" />

The first one makes the project system recognize the IISExpress launch command, the second one removes ANCM from the host config.

I see no issues with intellisense/code completion/breakpoints/etc in VS so far. Even mouse-overing in cshtml during debugging seems to work just fine.

There is some interference between netsdk and webapplication publishing that can be resolved with:

  <PublishProfileImported>true</PublishProfileImported>

Right-click publishing from VS still does not work and the pubxml has to be hand-crafted (or just reuse one from a non-sdk project). msbuild /t:Restore,Rebuild /p:DeployOnBuild=true /p:PublishProfile=FolderProfile.pubxml works fine for file system publish. Not much of a pain point here since pubxml rarely changes and the publish is usually scripted.

Minimal working csproj:

<Project>
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <OutputPath>bin\</OutputPath>
    <TargetFramework>net48</TargetFramework>
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
    <PublishProfileImported>true</PublishProfileImported>
  </PropertyGroup>
  <ItemGroup>
    <ProjectCapability Include="DotNetCoreWeb" />
    <ProjectCapability Include="SupportsSystemWeb" />
  </ItemGroup>
  <!-- add your packagereference/content/etc includes here -->
  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
  </PropertyGroup>
  <!-- order is important! -->
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" />
</Project>
BillHiebert commented 3 years ago

@bachratyg Do things (work better if you remove the explicit imports of sdk props and targets, and and change the Project element to this <Project Sdk="Microsoft.NET.Sdk.Web">

You can remove the DotNetCoreWeb ProjectCapability but you still need the SupportsSystemWeb capability to get Razor working and disable the ANCM support.

bachratyg commented 3 years ago

@BillHiebert if the sdk import is implicit then the WebApplication.targets import would come before Sdk.targets and that causes some issues. The sdk import acts as a replacement for Microsoft.CSharp.targets in the old project format and initializes some properties that WebApplication.targets depends on e.g. TargetFrameworkVersion. Otherwise some dependent properties would have to be initialized manually e.g. DeployDefaultTargetFrameworkVersion is needed for publish to work.

I have not even tried to go for Sdk.Web in place of plain Sdk to keep possible side effects to a minimum. At first glance Sdk.Web would import lots of things (other capabilities, analyzers, default imports, folder structure) that are relevant for AspNetCore but not for legacy AspNet. It also screws up the publish output.

Design time Razor seems to work just fine without Sdk.Web, though I'd prefer to do some more testing before drawing conclusions.

anderslaub commented 3 years ago

I am finally using SDK style for classic asp.net mvc projects without red squiggles or any other issues now.

The last piece of the puzzle for my setup was adding the ProjectCapability SupportsSystemWeb - this removed the red squiggles and Intellisense exceptions from Razor Views in Visual Studio.

However now I am wondering when and in which version of Visual Studio that SupportsSystemWeb was introduced?

I've found this list of supported Project Capabilities here - but this list hasn't been updated since 2019. Beside being mentioned here then SupportsSystemWeb seems undocumented.

Can someone help shed light on the SupportsSystemWeb Project Capability?

Also for anyone interested, a working .csproj for a "classic" ASP.NET MVC project can really be this short:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <OutputType>Library</OutputType>
   </PropertyGroup>
  <ItemGroup>
    <ProjectCapability Include="SupportsSystemWeb" />
    <PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.4" />
  </ItemGroup>
</Project>

For WebPublish, then instead of adding a dependency directly in the .csproj by importing the target, then I use a custom target that imports Microsoft.WebApplication.targets.

This target is imported by the project via directory.build.targets - see an example of the target here.

This approach ensure the load order while also keeping the .csproj free from VS build tools dependencies.

tompazourek commented 3 years ago

@anderslaub Thank you very much for sharing this! It indeed seems to fix the Razor IntelliSense issue, it finally looks like a viable solution is here.

I tried it in a branch of my sample repo AspNetMvcOnSdk feature/project-capability. And the squiggles are gone both when using ReSharper IntelliSense and when using the built-in VS IntelliSense. That's really great!

Fed03 commented 3 years ago

Thanks for the very interesting thread. Sadly, I can not get rid of the HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure problem even with the <ProjectCapability Include="SupportsSystemWeb" />.

Any ideas?

This is my CSPROJ

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>net471</TargetFramework>
        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
        <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
        <OutputType>Library</OutputType>
    </PropertyGroup>
    <PropertyGroup> 
        <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
        <OutputPath>bin\</OutputPath>
    </PropertyGroup>
    <ItemGroup>
        <ProjectCapability Include="SupportsSystemWeb" />
    </ItemGroup>
    <ItemGroup>
        <Reference Include="System.Web" />
    </ItemGroup>
    <ItemGroup>
        <Compile Update="Global.asax.cs">
            <DependentUpon>Global.asax</DependentUpon>
        </Compile>
    </ItemGroup>
</Project>
anderslaub commented 3 years ago

@Fed03 If you do get far enough to get a http status code then it is not build related but some configuration.

I usually extend an existing web app when using classic ASP.NET MVC. Here I publish to a folder and use attach to process for debugging (typically a process in a container nowadays) so I apologize for not considering F5 Debugging in the slimmed down csproj file example above.

However, out of curiosity I tried to create a new ASP.NET Framework MVC project using the old ASP.NET Framework MVC Visual Studio project template.

To make F5 Debugging work I had to add ProjectCapability DotNetCoreWeb and ensure OutputPath is bin\ - similar to what @bachratyg shows further up this thread.

  <PropertyGroup>
...
    <OutputPath>bin\</OutputPath>
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
  </PropertyGroup>
...
  <ItemGroup>
    <ProjectCapability Include="DotNetCoreWeb" />
...

2021-01-15 20_58_38-Home Page - My ASP NET Application - Work - Microsoft​ Edge

Full SDK Style csproj file for the "classic" Visual Studio ASP.NET Framework MVC Project Template:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <OutputType>Library</OutputType>
    <OutputPath>bin\</OutputPath>
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
  </PropertyGroup>
  <ItemGroup>
    <ProjectCapability Include="DotNetCoreWeb" />
    <ProjectCapability Include="SupportsSystemWeb" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Web" />
    <PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.7" />
    <!--old-school packages used by the old ASP.NET Framework MVC project template-->
    <PackageReference Include="bootstrap" version="3.4.1" targetFramework="net48" />
    <PackageReference Include="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net48" />
    <PackageReference Include="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.11" targetFramework="net48" />
    <PackageReference Include="WebGrease" version="1.6.0" targetFramework="net48" />
    <PackageReference Include="Modernizr" version="2.8.3" targetFramework="net48" />
    <PackageReference Include="Microsoft.Net.Compilers" Version="3.2.1" />
    <PackageReference Include="Antlr" version="3.5.0.2" targetFramework="net48" />
    <PackageReference Include="Newtonsoft.Json" version="12.0.1" targetFramework="net48" />
  </ItemGroup>

  <!-- target that copies roslyn files to bin/roslyn-->
  <Target Name="CopyRoslynCompilerFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory">
    <Copy SourceFiles="$(CscToolPath)\*" DestinationFolder="$(OutputPath)roslyn" ContinueOnError="true" SkipUnchangedFiles="true" Retries="0" />
  </Target>

</Project>

note that the package references and custom target to copy over the roslyn files are all specific for the old ASP.NET MVC example project template and it's configuration - these are not related to SDK style project format or VS debugging as such.

Hope it helps!

3nth commented 3 years ago

@bachratyg @anderslaub thanks so much!

I was able to get this working for both VS run/debug as well as a CI build/publish.

I started with @anderslaub example, but the CopyRoslynCompilerFilesToOutputDirectory not work for me. Files didn't get copied, so VS complained the roslyn files were not found. Could not figure this one out. Likely, because $(CscToolPath) does not exist for:

<PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="3.6.0" />

My understanding is we should be using this package instead of Microsoft.Net.Compilers going forward.

I am mostly using @bachratyg example, but for publish to work I had to add a few standard items:

<ItemGroup>
  <Content Include="Global.asax" />
  <Compile Update="Global.asax.cs">
    <DependentUpon>Global.asax</DependentUpon>
  </Compile>
  <Content Include="Scripts\**" />
  <Content Include="Content\**" />
  <Content Include="**\*.cshtml" Exclude="obj/**;bin/**" />
  <Content Include="**\web.config" Exclude="obj/**;bin/**" />
  <Content Include="Properties\webjobs-list.json" />
  <Content Include="ApplicationInsights.config" />
</ItemGroup>

I did not need to make any changes to my existing publish profile:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your Web project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <PublishProvider>FileSystem</PublishProvider>
    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish />
    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <publishUrl>../publish/web</publishUrl>
    <DeleteExistingFiles>True</DeleteExistingFiles>
    <PrecompileBeforePublish>True</PrecompileBeforePublish>
    <EnableUpdateable>False</EnableUpdateable>
    <DebugSymbols>False</DebugSymbols>
    <WDPMergeOption>MergeAllOutputsToASingleAssembly</WDPMergeOption>
    <UseMerge>True</UseMerge>
    <SingleAssemblyName>AppCode</SingleAssemblyName>
    <DeleteAppCodeCompiledFiles>True</DeleteAppCodeCompiledFiles>
  </PropertyGroup>
</Project>

For launch with IIS Express, needed a launchsettings.json file:

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "https://localhost:<PORT>/",
      "sslPort": <PORT>
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

If you are using npm, you want to add this. VS hangs processing all the files in node_modules otherwise.

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);node_modules\**</DefaultItemExcludes>
</PropertyGroup>

You can still include files as needed for publish:

<ItemGroup>
  <Content Include="node_modules\jquery\dist\jquery.min.js" />
</ItemGroup>
Fed03 commented 3 years ago

@anderslaub many, many thanks! sadly the ANCM issue seems related to how Rider creates the applicationhost.config file. It seems it ignores the <ProjectCapability Include="SupportsSystemWeb" /> directive, since with VS got this right

bachratyg commented 3 years ago

@Fed03 A ProjectCapability is a simple magic word that tells the IDE to enable some feature. What that means is entirely up to the IDE implementation.

bhugot commented 3 years ago

Someone know how to make it work with owin?

bachratyg commented 3 years ago

@bhugot It should work as is. Do you see some issue?

bhugot commented 3 years ago

It's ok found the problem was missing a package

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net472</TargetFramework>
    <OutputType>Library</OutputType>
    <OutputPath>bin\</OutputPath>
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
    <AppConfig>Web.config</AppConfig>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
  </PropertyGroup>
  <ItemGroup>
    <ProjectCapability Include="DotNetCoreWeb" />
    <ProjectCapability Include="SupportsSystemWeb" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Web" />
    <PackageReference Include="Microsoft.AspNet.WebApi.Owin" Version="5.2.7" />
    <PackageReference Include="Microsoft.AspNet.WebApi.WebHost" Version="5.2.7" />
    <PackageReference Include="Microsoft.Owin.Host.SystemWeb" Version="4.1.1" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />

  </ItemGroup>
 <Target Name="UpdateWebConfigBindingRedirects" AfterTargets="CopyFilesToOutputDirectory">
    <Copy SourceFiles="$(OutDir)$(AssemblyName).dll.config" DestinationFiles="web.config" />
  </Target>
</Project>
PureKrome commented 3 years ago

Great to see that this thread is active! (and I've been stalking this thread foe ages, now)

So .. currently ... is there an official MS-Doc page that explains all of this process in a confirmed process/way?

or is this still an experimental process, which is having various levels of success?

CZEMacLeod commented 3 years ago

Just used this technique to great effect. Some issues I found: I had to add these properties to the project file

<PlatformTarget>x64</PlatformTarget>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>

As one of my NuGet packages had a reference file and native runtimes for x86 and x64 I also added "use64Bit": true, to launchSettings.json

    "profiles": {
        "IIS Express": {
            "commandName": "IISExpress",
            "launchBrowser": true,
            "use64Bit": true,
            "environmentVariables": {
                "ASPNETCORE_ENVIRONMENT": "Development"
            }
        }
    }

I put my required web.config in app.config and added the following to the project

  <PropertyGroup>
    <AppConfig>app.config</AppConfig>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>    
  </PropertyGroup>

  <Target Name="UpdateWebConfigBindingRedirects" AfterTargets="CopyFilesToOutputDirectory">
    <Copy SourceFiles="$(OutDir)$(AssemblyName).dll.config" DestinationFiles="web.config" />
  </Target>

This enables automatic binding redirects for the project to be merged on build with your app.config to build a web.config on the fly. This may have issues if a nuget package wants to apply a web.config.*.xdt to install or uninstall but I'm sure people can work around this by copying any needed code out.

I also used both

<PackageReference Include="Microsoft.Net.Compilers.Toolset" Version="3.7.0" PrivateAssets="All"/>
<PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="3.6.0" />

This seems to be working fine for me with the CopyRoslynCompilerFilesToOutputDirectory target. The Toolset sets the build time compilers, and the DNCP adds the CodeDom compilers for 'runtime' use.