Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Web API controller definition doc #6003

Merged
merged 33 commits into from
Apr 24, 2018

Conversation

scottaddie
Copy link
Member

@scottaddie scottaddie commented Apr 17, 2018

Addresses #5401

This is a new doc explaining the various ways to create a Web API controller. The ASP.NET Core 2.1 [ApiController] attribute is covered in it.

Internal Review Page

@scottaddie scottaddie added the WIP label Apr 17, 2018
@scottaddie scottaddie changed the title [WIP] Add Web API controller definition doc Add Web API controller definition doc Apr 19, 2018
@scottaddie scottaddie removed the WIP label Apr 19, 2018
@@ -0,0 +1,113 @@
---
title: Define a controller in ASP.NET Core Web API
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a bone to pick with this branding @DamianEdwards @danroth27 are we still using the Web API branding? If I'm wrong about this I'll just go away 😆

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't use "ASP.NET Core Web API". Suggested title: "Building web APIs with ASP.NET Core"


This document explains when it's most appropriate to use each option.

## Derive class from Controller
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The document seems focused on APIs, I think it's good to do a comparison, but explain that Controller is recommended for HTML and Razor.

To most users this won't make a big difference, but it's possible in the future we'd ship a remixed framework that doesn't include Controller by default.


[!code-csharp[](../web-api/define-controller/samples/WebApiSample.Api/Controllers/ProductsController.cs?name=snippet_ControllerSignature&highlight=2)]

This attribute is commonly coupled with either `ControllerBase` or `Controller` to gain access to useful methods and properties. `ControllerBase` provides access to methods such as [CreatedAtAction](/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.createdataction) and [File](/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.file). `Controller` provides access to methods such as [Json](/dotnet/api/microsoft.aspnetcore.mvc.controller.json) and [View](/dotnet/api/microsoft.aspnetcore.mvc.controller.view).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also create your own base class and slap [ApiController] on it. There's nothing magic about Controller or ControllerBase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also create your own base class and slap [ApiController] on it. There's nothing magic about Controller or ControllerBase.

Can you suggest why you'd want to do that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, lots of folks like to do one of two things:

  1. Give us lots of specific feedback about specific action-result-creating methods they want to see or change
  2. Create an ApiController base class because they like that idea

Users can solve both of these problems for themselves. They can create their own base class that either inherits from ControllerBase, slap [ApiController] on it and they are good to go.


### Binding source parameter inference

Inference rules are applied for the default data sources of action parameters. The binding source attributes behave as follows:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think before digging into the details it would be good to show an example and explain the common patterns. Most APIs will bind a parameter (or two from the route) - usually an int or string, and a parameter or two from the query string - usually a simple type, and usually a complex type from the body.

It would be good to show how the [ApiController] attribute cleans up the code by inferring the details of the idiomatic approach for binding in APIs


[!code-csharp[](../web-api/define-controller/samples/WebApiSample.Api/Controllers/TestController.cs?name=snippet_ActionsCausingExceptions)]

* **[[FromForm]](/dotnet/api/microsoft.aspnetcore.mvc.fromformattribute)** is inferred for action parameters of type [IFormFile](/dotnet/api/microsoft.aspnetcore.http.iformfile) and [IFormFileCollection](/dotnet/api/microsoft.aspnetcore.http.iformfilecollection).
Copy link
Member

@rynowak rynowak Apr 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to add that [FromForm] won't be inferred for any simple or user-defined types. If you want to bind form data in an api controller, you should tell us about it because it's not super common

[HttpGet("{id}")]
[ProducesResponseType(typeof(Order), 200)]
[ProducesResponseType(404)]
public IActionResult GetById(int id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use ActionResult<Order>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That allows you to remove the [ProducesResponseType] attribute when it's a 200.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a 2.0 version of the sample app, which is why it doesn't use ActionResult.

@scottaddie
Copy link
Member Author

@rynowak Please take another look.


## Derive class from Controller

Inherit from the [Controller](/dotnet/api/microsoft.aspnetcore.mvc.controller) class in a controller that needs to support HTML and Razor in addition to web API actions. Examples that require `Controller` inheritance include returning MVC views or [invoking view components](xref:mvc/views/view-components#invoking-a-view-component-directly-from-a-controller).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in a controller that needs to support HTML and Razor in addition to web API actions.

I don't really know what that's a topic. You certainly could write a controller that serves both APIs and views, but I don't think we'd recommend that users do this on purpose.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I add a note explaining this approach isn't recommended? It's here since the project template used to derive from Controller.

Copy link
Member

@rynowak rynowak Apr 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of what it used to derive from, I don't understand why we would discuss it as a controller that needs to support HTML and Razor in addition to web API actions - this isn't something we've ever really told people to do. It's not explicitly recommended or disrecommended, which is why I'm suprised to see it getting coverage here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danroth27 Thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 to @rynowak's comment. I don't think we need to discuss deriving from Controller in this topic or anything views related.

[!code-csharp[](../web-api/define-controller/samples/WebApiSample.Api/Controllers/ProductsController.cs?name=snippet_ControllerSignature&highlight=2)]

This attribute is commonly coupled with either `ControllerBase` or `Controller` to gain access to useful methods and properties. `ControllerBase` provides access to methods such as [CreatedAtAction](/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.createdataction) and [File](/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.file). `Controller` provides access to methods such as [Json](/dotnet/api/microsoft.aspnetcore.mvc.controller.json) and [View](/dotnet/api/microsoft.aspnetcore.mvc.controller.view). Another approach is to create a custom base controller class annotated with the `[ApiController]` attribute.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@scottaddie scottaddie merged commit d771655 into master Apr 24, 2018
@scottaddie scottaddie deleted the scottaddie/define-controller-doc branch April 24, 2018 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants