How to use IActionResult in .NET Framework 4.6.1? - c#

I have been searching around for an answer to this the last couple of hours without any success. I´m relatively new to programming so please go easy on me :-)
My problem is that it seems that I can´t use IActionResult in one of my projects in my solution which is targeting .NET Framework 4.6.1 but in the same solution (different project) targeting .NET Standard 2.0 I can use it.
I have tried to install exactly the same Nuget packages and everything looks exactly the same except for what framework that is targeted.
I just want to write Azure Functions using IActionResults like:
public static async Task<IActionResult> MyFuntcion([HttpTrigger(AuthorizationLevel.Function, "get", Route = null")]HttpRequest req, TraceWriter log)
{
//Do some stuff then redirect
}
I'm guessing that my targeted framework is whats causing me to not be able to use IActionResult, but I don't understand why.
Any help would be much appreciated, especially if one might know how to make this work.
Thank you

Short Version
You can't use an IActionResult in a Full Framework MVC or Web API as a result object. You'll have to map it to the appropriate type first. You should probably not use IActionResult in your class libraries, let the core project handle with return types
But ASP.NET Core doesn't require the .NET Core runtime, it can target the Full Framework as well. Perhaps you can use an ASP.NET Core project targeting the Full framework for your main project?
Explanation
ASP.NET Core is the "new" name for ASP.NET 5. It's a new framework that merges the MVC and Web API stacks and was built to run on both the older Full framework and what was then called DNXCore. Both names changed to ASP.NET Core 1.0 and Core .NET 1.0, leading to the confusion we have today.
Before ASP.NET Core, ASP.NET MVC and Web API were two different stacks, they used different controller base classes and returned different results. ASP.NET MVC used the abstract ActionResult class and Web API used the IHttpActionResult interface. Using an interface means it's a lot easier to test and mock the results, among other things. It also means that classes that implement it don't have to handle potentially unneeded properties and base methods.
In ASP.NET Core, the web framework, the entire stack was redesigned and now there's a single stack with a single base interface for results, IActionResult. Core's ActionResult is the default implementation but anyone can create a different implementation. RedirectResult for example doesn't need a Content property so it doesn't have one.
This interface is available to every .NET Standard 2.0 library as long as the appropriate package are added.
That doesn't mean it can be used as the actual return type in ASP.NET MVC 6 or Web API 2 projects though, because neither MVC's ActionResult nor Web API's IHttpActionResult implement it. One would have to write code to map from a concrete IActionResult instance to a concrete MVC ActionResult or Web API IHttpActionResult instance.
If your main project is ASP.NET Core though, you can use the interface whether it runs on the Full or Core framework.
.NET Standard
.NET Standard is a set of API specifications not a specific runtime. Each version specifies a set of classes and APIs that should be provided by a runtime that complies with that Standard version. When one creates a .NET Standard 2.0 library it means the code can use any of the classes and APIs defined in the 2.0 version.
Adding just the interface
IActionResult is not part of .NET Standard 2.0. It's provided by a package Microsoft.AspNetCore.Mvc.Abstractions.

SOLUTION.
I needed to install Microsoft.AspNetCore.Mvc package in order to get it to work.
Sry for my newbie questions and thank you very much for the help.
Edit: As #PanagiotisKanavos writes its enough with the Microsoft.AspNetCoreMvc.Abstractions package for IActionResult. Needed some other stuff beyond that so went for the whole package.

Does it even exist in .net? It seems to exist only in .net core.
Source on Microsoft:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.iactionresult?view=aspnetcore-2.1
See "Applies to" on that page.

Related

What is AddEndpointsApiExplorer in ASP.NET Core 6

I'm upgrading an ASP.NET Core API project from v5 to v6.
Service config in v5:
services.AddSwaggerGen();
Service config in v6:
builder.Services.AddEndpointsApiExplorer(); // what is this?
builder.Services.AddSwaggerGen();
What is AddEndpointsApiExplorer? Everything works as expected whether I add it or not.
I use the "ASP.NET API Versioning" library. Are they related? If so, must I use both, just the library, or is the library unnecessary now?
AddEndpointsApiExplorer is for Minimal APIs whereas AddApiExplorer requires, at least, MVC Core. For API projects, AddControllers calls AddApiExplorer on your behalf.
But Why Does Everything Still Work With AddEndpointsApiExplorer?
With the introduction of Endpoint Routing, everything in the routing system boils down to an Endpoint. ASP.NET Core uses the Application Model, namely ApplicationModel, ControllerModel, and ActionModel, to create Endpoint instances and register them with the routing system. Minimal APIs, however, use a builder to directly create and register individual Endpoint instances.
The default API Explorer implementation provides a IApiDescriptionProvider that builds ApiDescription instances from the Application Model. Minimal APIs do not have an Application Model so there is nothing to build ApiDescription instances from. The API Explorer provides these descriptions, which are commonly used by tools such as OpenAPI generators. Without any descriptions, there would be no support for Minimal APIs and OpenAPI; that would be bad (or, at least, certainly not accepted by developers). To address that, the ASP.NET Core team created a second IApiDescriptionProvider that only considers Endpoint.
If Everything is an Endpoint, Why Not Merge Implementations?
There's two parts to this answer. First, changing the original IApiDescriptionProvider implementation would introduce a public, breaking change. At a minimum, new constructor arguments would be required. Since it was a major version bump, this approach wasn't off the table, but it turns out to be irrelevant. The bigger issue is that the original IApiDescriptionProvider implementation and AddApiExplorer live in and depend on MVC Core. Minimal APIs only require the routing abstractions. There is no way to merge the two without adding unnecessary coupling. To address this problem, AddEndpointsApiExplorer was added which adds an implementation that only requires an IApiDescriptionProvider implementation based on bare bones Endpoint definitions from the routing system.
If AddEndpointsApiExplorer exists and I call it, do I even need AddApiExplorer anymore? Maybe. The metadata exposed and available on Minimal API Endpoint instances is much lighter than the Application Model; after all, they are minimal. Behind the scenes, a IApiDescriptionGroupCollectionProvider implementation takes a sequence of IApiDescriptionProvider instances. If AddEndpointsApiExplorer and AddApiExplorer are called, then both providers will execute. If only AddEndpointsApiExplorer is called, it will work with regular 'ol controllers, but the descriptions' information fidelity might be less than what you are accustomed to. If you are only authoring Minimal APIs, then AddEndpointsApiExplorer is required if you want API Explorer support.
The fidelity between the two methods is improving even more in .NET 7.0. In some future release, it's possible we might see these approaches coalesce into one.
TLDR; .AddEndpointsApiExplorer() was created to support Minimal Api's.
Searching the doc's via google shows a number of pages that include a call to .AddEndpointsApiExplorer(). But no mention of why you need it, or if it is required when migrating from a v5 project. The documentation is definitely lacking.
Working backwards from the source code & git blame, I found the related project. So the answer appears to be related to support for Minimal Api's.
I believe some new services were created to extract return type information from these new minimal api's, in a way that might apply in a more general way when using Endpoint Routing without MVC.
If you are using MVC, perhaps via .AddControllers(), .AddApiExplorer() would be called for you. Providing the services that swagger depends on for describing controller actions. If that's all you need, then this new api call doesn't seem to be required.
While the documentation for using swagger with minimal api's includes a call to .AddEndpointsApiExplorer(). Even that doesn't explain exactly why it is required.
Why does .AddEndpointsApiExplorer() exist at all? Why were the new features excluded from .AddApiExplorer()? Why was this method rename left out of other documentation for v6?
Perhaps we should create an issue on https://github.com/dotnet/aspnetcore/ or https://github.com/dotnet/AspNetCore.Docs/ to ask for clarification so that others don't have to ask these questions.
TL;DR
Only use AddEndpointsApiExplorer if you use v6's "minimal APIs", which look like this:
app.MapGet("/", () => "Hello World!");

.net 6.0 Core migration changes JSON from framework. Polymorphism restriction

We're migrating a .net 4.7 framework solution to .net 6.0 (core). The solution interfaces with a React front-end system, and a NodeJS MongoDb back-end, so we have gone with the MVC model and copied our code to new projects.
Our problem is the change in design relating the the JSON controller response. In the live system, the JSON sent to the external system is fully resolved to the polymorphic version, while in the new core system it is resolved to the base class. Here's a snip of the response class:class start showing interface used to send the screen data to display
Postman shows us that when we have the interface swapped with a base class, the JSON response is the base class. Interestingly, swapping it for an interface has the default JSON response (System.Text.Json) use the properties in the interface, while Newtonsoft.Json correctly renders the full/inherited class with JsonConvert.SerializeObject() versus JsonSerializer.Serialize().
We have changed the Program.cs to include "services.AddControllers().AddNewtonsoftJson();" which seems to get past our problem so far, but I'm assuming it should be possible to use the new library instead. Performance isn't an issue, but we are upgrading to stay on a strategic path.
We have looked at explanations like https://www.tutorialdocs.com/article/webapi-data-binding.html and https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-polymorphism but don't know the best way forward. Get rid of polymophism (composition instead of inheritance?) But then our system just exported the interface properties. We've also tried to validate our System.Runtime.Serialization annotations, but without success.
We'd appreciate guidance on a good approach to solve this.

ASP.NET Core API Versioning - Same controller for all versions

I have an ASP.NET Core 3.1 API and I am introducing a new version for one of my controllers.
I am using the Microsoft.AspNetCore.Mvc.Versioning NuGet package and I have set the new version to be the default version.
All my other controllers should work with both the old version (1.0) and the new version (1.1).
For example:
[ApiVersion("1.0", Deprecated = true)]
public class MySampleController
{
}
[ApiVersion("1.1")]
public class MyNewSampleController
{
}
[ApiVersion("1.0", Deprecated = true)]
[ApiVersion("1.1")]
public class AllOtherController
{
}
Questions:
Do I really have to add all versions to all controllers?
Is there a better/correct way of handling this?
I have tried to use [ApiVersionNeutral] but that does not seem correct and, according to the documentation, should only be used in special cases.
If I do not add the [ApiVersion] attribute, it defaults to the new 1.1 version and 1.0 no longer works.
Since this is my first SO question, I hope itfalls within the guidelines :)
Q: Do I really have to add all versions to all controllers?
A: Yes. API versions are discrete. A client should get exactly what they ask for and an appropriate error response if the server cannot satisfy the request.
Q: Is there a better/correct way of handling this?
A: There are several possible options. A better or more correct way of handling things is highly subjective. There are numerous factors and the final decision may simply come down to preference.
A common misconception is that API Versioning uses attributes. It really doesn't care about attributes, it's just one possibility and one that tends to resonate with developers as metadata. You have the choice to use out-of-the-box attributes, custom attributes, out-of-the-box conventions, or your own custom conventions.
The choice of how to apply the version metadata is typically of preference and practical management. A common scenario is to organize controllers in folders by API version. In several .NET languages, the folder name translates to part or all of the corresponding namespace. This arrangement is common enough that there is an out-of-the-box VersionByNamespaceConvention for it. For details, see the documentation. The By Namespace Sample also demonstrates how to up such a project end-to-end.
API version-neutral means that an API takes any and all versions, including none at all. It can mean you don't care about the API version or that you accept a whole range that you'll deal with yourself. It is really only meant to be used with APIs that never change over time. For example, a HTTP DELETE operation typically does not change over time or across versions.
It's not 100% clear what you mean by:
"If I do not add the [ApiVersion] attribute, it defaults to the new 1.1 version and 1.0 no longer works."
There are no defaults per se. This statement seems to imply that you have set the AssumeDefaultVersionWhenUnspecified option to true. You should not do that unless you have a very good reason to do so. That is probably one of the most abused features of API Versioning. A client must know the version it is asking for. Allowing a client to not specify a version and having things transition from 1.0 to 1.1 can break the client. The server can make no assumption that it won't. This feature was meant to grandfather in existing services that didn't previously have an explicit version defined. That scenario only exists when API Versioning is first enabled. As stated above, all controllers must have one or more discrete API versions, but the original set of APIs didn't have it explicitly defined. If this feature didn't exist, then the baseline set of clients that didn't know about an API version would break.

Is it possible to specify multiple assemblies for a Swashbuckle CustomAsset?

I am using Swashbuckle to embed Swagger documentation for our API into our .NET Web API 2.2 application (.NET 4.5). Up until now all the controllers have lived in the main Web API dll but as we start building out the API we are moving different version APIs to separate dlls.
When specifying a custom asset in Swashbuckle it is possible to specify 1 assembly for a resource path e.g. "v1" -> V1Assembly. However, I want to support the ability for the user to be able to view all API endpoints across all versions and assemblies. How do I make sure that this functionality is feasible with Swashbuckle? Essentially, I want a "all" or "index" endpoint on the help system to show all potential API Resources across all versioned assemblies.
My thought was a new feature that extends the SwaggerUiConfig to allow CustomAsset to accept an array of assemblies instead of just one so that we could interrogate multiple assemblies to generated the documentation instead of just the single one.
Any thoughts on how to accomplish this in the SwaggerConfig or otherwise?
If I understand correctly when you started versioning you ended up with multiple Web API.
You should consider refactoring your code using aspnet-api-versioning
All you will need to do in the controllers is identify them using something like:
[ApiVersion( "AreaOne" )]
https://github.com/Microsoft/aspnet-api-versioning/wiki/How-to-Version-Your-Service
For that Swashbuckle has full support.

How does the MVC framework know which controller to use when controllers are in a separate class library?

I've just created an MVC project using the .NET 4.5 framework with controllers in a separate class library.
I had previously thought that if the controllers are in separate class library you need to create a custom controller factory as discussed in this SO post. However, my controllers are being instantiated and are working fine without having to do this.
How does the framework (the newer ones at least) know to use the controllers in the separate class libary without being told to do so? All I needed to do was add a reference to the controllers project.

Categories

Resources