How can I find my dotnet mvc Controller's ApiVersion programmatically - asp.net-mvc

I'm using dotnet core 1.1. I have a web api with several controllers, which look like this:
[ApiVersion("1.0")]
[Route("v{version:apiVersion}/mycontroller")]
public class MyController : Controller
{
[HttpGet("action1")]
public string Get()
{ /* actual logic */ }
// More actions ...
}
I'd like to have a special controller which iterates through my controllers and print out the version and the route to them, like this:
MyController -- 1.0 -- /v1.0/mycontroller
MyOtherController -- 1.1 -- /v1.1/myothercontroller
But I can't figure out how to access the data at runtime. Thoughts?

Apologies for being late to the party, but the way to achieve this is to use the complimentary API Explorer package for API Versioning. This package is most commonly used for Swagger generation, but there is no direct coupling or usage of Swagger. You can use the API Explorer to enumerate all your controllers as well as their corresponding versions and routes.
In your scenario, you would integrate the required services with:
services.AddVersionedApiExplorer(
options =>
{
// add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
// note: the specified format code will format the version as "'v'major[.minor][-status]"
options.GroupNameFormat = "'v'VVV";
// note: this option is only necessary when versioning by url segment. the SubstitutionFormat
// can also be used to control the format of the API version in route templates
options.SubstituteApiVersionInUrl = true;
}
The controller you want to output the information should declare the IApiDescriptionGroupCollectionProvider and IApiVersionDescriptionProvider services in its constructor. The APIs will be grouped according to the GroupName property in the format specified by the API Explorer.
That should get you started. Let me know if you have more questions.

Related

Why does .NET Core Web API calls AddMVC() and UseMVC()?

When the scaffold for a .NET core Web API is used it includes:
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
in the ConfigureServices method and
app.UseMvc();
in the Configure method.
Why is this? A web API doesn't need "Model View Controller". It might only need "Model" and "Controller". I relate MVC very much to Views and Razor. Can these declarations be left out?
If we check the source code for the internal AddMvc extension we can see these things clearly:
public static IMvcBuilder AddMvc(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
var builder = services.AddMvcCore();
builder.AddApiExplorer();
builder.AddAuthorization();
AddDefaultFrameworkParts(builder.PartManager);
// Order added affects options setup order
// Default framework order
builder.AddFormatterMappings();
builder.AddViews();
builder.AddRazorViewEngine();
builder.AddRazorPages();
builder.AddCacheTagHelper();
// +1 order
builder.AddDataAnnotations(); // +1 order
// +10 order
builder.AddJsonFormatters();
builder.AddCors();
return new MvcBuilder(builder.Services, builder.PartManager);
}
In my opinion, for Web API, you probably need AddJSONFormatters() and AddCors(). However, you would also need AddMvcCore(). This includes stuff like routing, attributes, filters, result executors, model binders, controllers etc.
Refer to https://codingblast.com/using-web-api-asp-net-core-without-mvc-specific-stuff/
app.UseMvc() tells your app to add MVC to the request execution
pipeline. This will ensure that all requests to your web application
are routable to the MVC framework, meaning you can use controllers,
views and anything else contained within the MVC implementation
(action filters etc).
if you don't need view functionality then you
Don't create a web API controller by deriving from the Controller class. Controller derives from ControllerBase and adds support for views, so it's for handling web pages, not web API requests. There's an exception to this rule: if you plan to use the same controller for both views and APIs, derive it from Controller. The ControllerBase class provides many properties and methods that are useful for handling HTTP requests.
For more details checkout this link.
https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-2.2

Create one code client / flatten controllers with NSwag and AutoREST

I'm trying to create a code wrapper for an api with NSwag and Autorest.
Previously I was using Swashbuckle to generate the swagger file. It generated the swagger file with operationIds in the format actionMethod. This resulted in Autorest generating a code client that was 1-deep. All of the actions were on the top-level class.
For various reasons, I needed to change swagger generation to NSwag. This generates operationIds in the format controller_actionMethod. This results in AutoRest creating a composite class that exposes separate classes with actions for each controller.
How can either
Change how NSwag generates the operationIds
Change how Autorest maps operationIds
Note: I know I can manually change the swagger.json, but I'd like to keep a consistent automated process for generating the code client.
There doesn't appear to be any readily available settings, but you can hook into the generation process of NSwag
https://github.com/RicoSuter/NSwag/wiki/Document-Processors-and-Operation-Processors#operation-processors
The operation processor
class FlattenOperationsProcessor: IOperationProcessor
{
public async Task<bool> ProcessAsync(OperationProcessorContext context)
{
context.OperationDescription.Operation.OperationId = $"{context.MethodInfo.Name}";
return true;
}
}
Then add it in Startup.cs
document.OperationProcessors.Add(new FlattenOperationsProcessor());
Not sure if this was available when the question was asked, but here is a pretty easy way to do it:
services.AddSwaggerGen(c =>
{
...
c.CustomOperationIds(d => d.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor ? controllerActionDescriptor.MethodInfo.Name : d.ActionDescriptor.AttributeRouteInfo?.Name);
});
The same can also be set via c.SwaggerGeneratorOptions.OperationIdSelector
Note that ActionDescriptor.AttributeRouteInfo?.Name is the default I used from the source code here

Is it possible to use ASP.NET Core Web API and Views with Razor and get Intellisense?

If I build a Web API Project in Asp.Net Core 1.x, and I want to build the front-end in the same Project or Solution, is it possible to create front-end pages and use Razor with Visual Studio's Intellisense?
The application is built around an API for public consumption, but since my application will use the same data, I thought it would make sense to consume my own API instead of building separate methods or constructs for API calls vs "regular" MVC (call the controller, gets the model data, return the view). A client will have their own front-end and get the data. I will have my own front-end, but I want it integrated in the same VS Solution.
One downside is I lose my Intellisense because I am building it around consuming the JSON returning from the API. I understand that an API is about returning data, not Views. I'm trying to get the best of all worlds and be more productive with Visual Studio features.
All I have read is older. SO has older question as well. I read a a lot about returning a View with an API, but I'm not sure I want that. I want to do like a normal non-Web API project and API project at the same time.
Is this possible?
My understanding is no/sort of because the whole point of Razor is that it is done on the server and the API is for clients outside your application. In other words, I'd need to build a controller that called my API controllers, so I get Intellisense which seems a bit redundant and harder work on the server.
Some possibilities:
Building REST APIs using ASP.NET Core with Razor syntax
ASP.NEt MVC using Web API to return a Razor view
asp.net mvc consuming asp.net web api end point
EDIT: This seems to be logical, https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/areas
EDIT: Here is what I did, using this as a guide:
https://msdn.microsoft.com/en-us/magazine/mt763233.aspx
I created an Area in my Project. Under this I created the name of an Area and under this I created Controllers, Views (and under this Home).
In my Startup.cs file I added,
app.UseMvc(routes =>
{
routes.MapRoute(name: "areaRoute",
template: "{area:exists}/{controller=Home}/{action=Index}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}");
});
The URL is localhost:port/AreaName
From within my Controller, I was able to reuse the services from my Service Layer, an abstraction I had decided on earlier in the project.
namespace books.Areas.Controllers
{
[Area("Books")]
public class HomeController : Controller
{
private readonly AppSettings _appSettings;
public HomeController(Microsoft.Extensions.Options.IOptions<AppSettings> appSettings)
{
_appSettings = appSettings.Value;
}
// GET: /<controller>/
public IActionResult Index()
{
var myConn = _appSettings.ConnectionString;
var getBooks = new BookLoanService(myConn);
return View(getBooks.GetAll());
}
}
}
This is the same Service Layer my API controller uses. The Service Layer has (I am using Dapper),
public List<books> GetAll()
{
using (IDbConnection db = new SqlConnection(_connectionString))
{
string SqlString = "SELECT TOP 5 last_name, first_name FROM books";
var myBooks = (List<books>)db.Query<books>(SqlString);
return myBooks ;
}
}
Once I was able to get my types, I was able to use Razor in my Index in my Area:
#model System.Collections.Generic.List<books>
#{
}
<html>
<body>
#foreach(var person in Model)
{
<ul><li>#person.last_name</li></ul>
}
</body>
</html>
Without modification, I am still able to use my api/values type of URL to get to my API, and I will be able to refresh part of my page after that initial server rendering by calling the API via Ajax.

Any way to get MVC Authorization statistics of an application?

I'm now building an application in MVC5. Data of different corporations are stored in the same database and people access them under the control of "[Authorize(...)]" and some other costumed filters. With the growing of controllers and actions, I'm more and more worried about the security, for example: is there any actions without authorization or with wrong authorization?
So the question is: Is there any
1. Report views in Visual Studio (might not designed to do the work)
2. Third part tools
3. Something else
that give a clear map of authorization of all controllers/actions? This is a critical work and I think there should be some solutions rather than check through all those code files.
Thanks.
I like to use FluentSecurity because of this. From their docs:
Ignoring missing configurations
By default FluentSecurity will throw an exception if a missing
configuration is encountered for a controller action. If you don't
want FluentSecurity to handle security for all controllers you can
tell it to ignore missing configurations. You can do this by adding
configuration.IgnoreMissingConfiguration(); to your configuration
expression.
It puts security configurations in a single file, makes them unit testable, and is generally useful. There is a small learning curve to figuring out how to bootstrap it and get it set up. You can install it and get going quickly using nuget.
Besides this, there arent really any tools that I know of that can do the reporting that you are asking about... unless you want to write a battery of unit tests against each actionmethod:
[TestFixture]
public class AccountControllerTests {
[Test]
public void Verify_ChangePassword_Method_Is_Decorated_With_Authorize_Attribute() {
var controller = new AccountController();
var type = controller.GetType();
var methodInfo = type.GetMethod("ChangePassword", new Type[] { typeof(ChangePasswordModel) });
var attributes = methodInfo.GetCustomAttributes(typeof(AuthorizeAttribute), true);
Assert.IsTrue(attributes.Any(), "No AuthorizeAttribute found on ChangePassword(ChangePasswordModel model) method");
}
}

ServiceStack new service side by side ASP.NET MVC website

In the examples for ServiceStack I don't see a single application that is ASP.NET MVC website first and then made ServiceStack service second.
Let's take a very simple ASP.NET MVC web application that renders products through Views. It uses controllers, views, models and viewmodels.
Let's say we have a model of Product which gets persisted into a document DB. Let's assume we have a viewmodel of ProductViewModel which gets mapped from Product and display within MVC Razor View/PartialView.
so this is a web side of things..now let's assume we want to add a service returning products to various clients like the Windows 8 applications.
Should the request/response classes be completely disconnected from what we already have? Our ProductViewModel might already contain everything we want to return from the service.
Since we already have Product (model class) we can't have another Product class in the API namespace..well we could but that makes things unclear and I'd like to avoid that.
So, should we introduce standalone ProductRequest class and ProductRequestResponse (inherits ProductViewModel) class in the API namespace?
Like so ProductRequestResponse : ProductViewModel?
What i'm saying is, we already have the Model and ViewModel classes and to construct Request and Response classes for the SS service we would have to create another two files, mostly by copying everything from the classes we already have. This doesn't look DRY to me, it might follow the separation of concerns guidelines but DRY is important too, actually more than separating everything (separating everything leads to duplication of code).
What I would like to see is a case where a web application has already been made, it currently features Models and ViewModels and returns the appropriate Views for display on the Web but can be extended into a fully functional service to support programmatic clients? Like AJAX clients etc...with what we already have.
Another thing:
If you take a look at this example https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/ServiceStack.MovieRest/MovieService.cs
you will see there is Movie Request class and Movies Request class (one for single movie request, the other one for a list of movies). As such, there are also two services, MovieService and MoviesService, one dealing with requests for a single movie, the other one for a genre of movies.
Now, while I like SS approach to services and I think it is the right one, I don't like this sort of separation merely because of the type of request. What if I wanted movies by director? Would I be inventing yet another request class having a Director property and yet another service (MoviesByDirector) for it?
I think the samples should be oriented towards one service. Everything that has to deal with movies need to be under one roof. How does one achieve that with ServiceStack?
public class ProductsService : Service
{
private readonly IDocumentSession _session;
private readonly ProductsHelperService _productsHelperService;
private readonly ProductCategorizationHelperService _productCategorization;
public class ProductRequest : IReturn<ProductRequestResponse>
{
public int Id { get; set; }
}
// Does this make sense? 
// Please note, we use ProductViewModel in our Views and it holds everything we'd want in service response also
public class ProductRequestResponse : ProductViewModel
{
}
public ProductRequestResponse GetProducts(ProductRequest request)
{
ProductRequestResponse response = null;
if (request.Id >= 0)
{
var product = _session.Load<Product>(request.Id);
response.InjectFrom(product);
}
return response;
}
}
The Service Layer is your most important Contract
The most important interface that you can ever create in your entire system is your external facing service contract, this is what consumers of your service or application will bind to, i.e. the existing call-sites that often won't get updated along with your code-base - every other model is secondary.
DTOs are Best practices for remote services
In following of Martin Fowler's recommendation for using DTOs (Data Transfer Objects) for remote services (MSDN), ServiceStack encourages the use of clean, untainted POCOs to define a well-defined contract with that should kept in a largely implementation and dependency-free .dll. The benefits of this allows you to be able to re-use typed DTOs used to define your services with, as-is, in your C#/.NET clients - providing an end-to-end typed API without the use of any code-gen or other artificial machinery.
DRY vs Intent
Keeping things DRY should not be confused with clearly stating of intent, which you should avoid trying to DRY or hide behind inheritance, magic properties or any other mechanism. Having clean, well-defined DTOs provides a single source of reference that anyone can look at to see what each service accepts and returns, it allows your client and server developers to start their work straight away and bind to the external service models without the implementation having been written.
Keeping the DTOs separated also gives you the freedom to re-factor the implementation from within without breaking external clients, i.e. your service starts to cache responses or leverages a NoSQL solution to populate your responses with.
It's also provides the authoritative source (that's not leaked or coupled inside your app logic) that's used to create the auto-generated metadata pages, example responses, Swagger support, XSDs, WSDLs, etc.
Using ServiceStack's Built-in auto-mapping
Whilst we encourage keeping separate DTO models, you don't need to maintain your own manual mapping as you can use a mapper like AutoMapper or using ServiceStack's built-in Auto Mapping support, e.g:
Create a new DTO instance, populated with matching properties on viewModel:
var dto = viewModel.ConvertTo<MyDto>();
Initialize DTO and populate it with matching properties on a view model:
var dto = new MyDto { A = 1, B = 2 }.PopulateWith(viewModel);
Initialize DTO and populate it with non-default matching properties on a view model:
var dto = new MyDto { A = 1, B = 2 }.PopulateWithNonDefaultValues(viewModel);
Initialize DTO and populate it with matching properties that are annotated with the Attr Attribute on a view model:
var dto = new MyDto { A=1 }.PopulateFromPropertiesWithAttribute<Attr>(viewModel);
When mapping logic becomes more complicated we like to use extension methods to keep code DRY and maintain the mapping in one place that's easily consumable from within your application, e.g:
public static class MappingExtensions
{
public static MyDto ToDto(this MyViewModel viewModel)
{
var dto = viewModel.ConvertTo<MyDto>();
dto.Items = viewModel.Items.ConvertAll(x => x.ToDto());
dto.CalculatedProperty = Calculate(viewModel.Seed);
return dto;
}
}
Which is now easily consumable with just:
var dto = viewModel.ToDto();
If you are not tied specifically to ServiceStack and just want "fully functional service to support programmatic clients ... with what we already have", you could try the following: Have your controllers return either a ViewResult or a JsonResult based on the request's accept header - Request.AcceptTypes.Contains("text/html") or Request.AcceptTypes.Contains("application/json").
Both ViewResult and JsonResult are ActionResult, so the signature of actions remains the same, and both View() and Json() accept a ViewModel. Furthermore, if you have a ControllerBase you can make a base method (for example protected ActionResult RespondWith(Object viewModel)) which calls either View() or Json() so the change to existing code is minimal.
Of course, if your ViewModels are not pure (i.e. have some html-specific stuff or you rely on some ViewBag magic) then it's a little more work. And you won't get SOAP or other binding types provided by ServiceStack, but if your goal is to support a JSON data interface with minimal code changes to the existing MVC app then this could be a solution.
Lp

Resources