I am building an API using Web API .NET 2, created a BaseController class which all other controllers inherit. I would like to apply API versioning using [ApiVersion()] attribute, however I don't want to decorate each controller class with same attributes if I have more than one version of API. Is there a way to set all possible API versions for all controllers? I tried to set attributes on BaseController class, but unfortunately attributes are not inherited by derived classes.
The ApiVersionAttribute intentionally is not inherited because if you use inheritance on your controllers, for example V2.Controllers.ValuesController inherits from V1.Controllers.ValuesController, you end up with two controllers with the same route that both implement 1.0, which is ambiguous and will produce an error.
There are several possible ways to achieve your goal:
Create your own attribute, extending ApiVersionsBaseAttribute, allow it to be inherited and apply it to a base class.
Create your own attribute, implement IApiVersionProvider, allow it to be inherited, and apply it to a base class.
Enumerate all controller types in your configuration setup and use a convention that applies one or more API versions to all controllers. options.Conventions.Controller(controllerType).HasApiVersion(1.0);. This will be unioned with an explicit attributes (ex: 1.1)
You can author a custom convention, which applies one or more API versions to all or specific controllers. Currently, the convention can only be applied to an entire controller, but per-action support will be available in the next major release (as there are breaking changes to the API, even though there is no visible change for most). For example, options.Conventions.Add(new MyConvention(new ApiVersion(1,0)));.
I hope that helps.
You can use ApiVersioning middleware as shown in below example
services.AddApiVersioning(
o =>
{
o.AssumeDefaultVersionWhenUnspecified = true );
o.DefaultApiVersion = new ApiVersion( 1,0);
} );
It sets default version for all controllers to be 1.0.
Also if version is not specified, the call will be routed to controller with default version.
If you want to create new version of existing controller, then you can specify the version attribute on that controller.
Hope this helps.
Related
EDIT: I'm aware of what attributes in general do, the question is for this specific attribute alone. Sorry for the confusion!
I've read the following question, along with this one, which point to how the attribute is used to ignore the generated swagger/swashbuckle documentation for specific methods or whole controllers. (documentation is the swagger page with all the api's listed I believe?)
But other than swagger/swashbuckle (which is a NuGet package), what other function does this attribute possess in ASP.NET?
When applied to a public method on a controller, it prevents that method from appearing in the swagger ui.
First of all, to clarify, an attribute in C# does not trigger anything by itself. External code searches for classes, methods or properties marked with a specific attribute, and act accordingly.
Of course, there are many building blocks in ASP.NET MVC, it can be confusing sometimes.
This attribute is used by Swagger to hide the endpoint.
Also usedd (in .NET core at least) by the given implementations of IApiDescriptionProvider and other related interfaces, but that would be effective only if you actually use them (by configuring them up in Startup.cs)
(for some more details and example, see https://andrewlock.net/introduction-to-the-apiexplorer-in-asp-net-core/)
This attribute helps to control the visibility. We can use this on the controller class or an action method when we want to hide that specific controller or action from showing in the swagger UI.
So I want to do some profiling on a bunch of controllers which inherit from System.Web.Http.ApiController. In the project that's doing the profiling, we're registering them with
builder.RegisterApiControllers(typeof(Web.Modules.AutofacModule).Assembly)
.As(type => new Autofac.Core.KeyedService("api", type));
Later on, I'm trying to register a decorator for each with
builder.RegisterDecorator<ApiController>(original => Decorate(original, profiler),
fromKey: "api");
where Decorate injects some profiling code via a DelegatingHandler and returns the original.
I can resolve the controllers just fine:
scope.ResolveKeyed<RegistrationController>("api");
but the profiling code is never invoked, nor is Decorate.
My first thought was that maybe I need to register the controller components as ApiController's, but dropping an .As<ApiController>() just below first snippet wasn't successful.
Any help would be super. This probably just boils down to my lack of Autofac-fu.
So I want to do some profiling on a bunch of controllers which inherit from System.Web.Http.ApiController.
This is impossible. This has nothing to do with Autofac, but with the way ASP.NET Web API is designed.
Even though Web API Controllers derive from a common base class, ASP.NET Web API requires the original controller type to be used. In other words, when it requests a HomeController from the IHttpControllerActivator, it expects that exact type (or a sub type), but not a sibling type (another ApiController derivative).
I think this limitation exists because Web API uses reflection to find the actual action methods. But when you return a decorator, those methods are gone, because a decorator applies composition instead of inheritance. This is very different from how ASP.NET MVC is designed. MVC actually does allow controllers to be decorated, as it always invokes the IController.Execute method. Implementation IController is therefore MVC's only requirement for controllers.
So even if you configure Autofac to wrap any ApiController derivatives in a Decorator, Web API simply won't let you.
The way to apply Cross-Cutting Concerns around the invocation of action methods in Web API is through the use of delegating handlers.
I am using WebAPI Help pages project from nuget to document my ASP.Net WebAPI services.
I have several controllers that have the [Authorize] attribute and several custom Attributes.
What I have not been able to achieve is to have the Attributes added to the documentation.
So if a Controller is marked as [Authorize], then the documentation for the controller would say something like "This XYZ Controller requires Authorization"
So my question is how can I modify the WebAPI help code, to document the attributes on my Controllers.
Model level attributes are working with no issue.
You can modify the installed XmlDocumentationProvider.cs at Areas\HelpPage\ for this. There modify the GetDocumentation(HttpControllerDescriptor controllerDescriptor) method. You can inspect any attributes that are decorated no the controller type controllerDescriptor.ControllerType and accordingly change the documentation.
When upgrading the HelpPage nuget package you might find doing the above inconvenient as you might want to override the contents with latest bits...so instead you can create a custom documentation provider inheriting from XmlDocumentationProvider and instead make a small modification to the installed HelpPageConfig.c file and mention to your custom provider.
I found this Post (How to extend where MVC looks for views) about changing the location of the View.
I was wondering if there's something similar for changing the location of the controller.
I just want to change the location of the class inside project and don't want to affect the url.
For example Instead of placing the Controller into
MyMvcProject\Controllers\
MyController1.cs
MyController2.cs
MyController3.cs
I want to achieve something like
MyMvcProject\MyGroup1\
MyController1.cs
MyController2.cs
MyMvcProject\MyGroup2\
MyController3.cs
and also support Areas:
MyMvcProject\Areas\MyGroup3\
MyController4.cs
Is it possible to achieve this? And if yes, where can I find documentation about it?
You can do what you want, and it doesn't require any special configuration, because ASP.NET MVC does not care about where you put your controllers. First, controllers are located using reflection, so the name of the folder where you put your controllers is irrelevant. Controllers are searched by type name and optionally by namespace (for disambiguation). You can even have controllers in separate projects/assemblies. As long as the controller ends up in an assembly in the bin folder then it's searchable by the framework.
As mentioned above, you'll need to create a controller factory to support your custom resolution. Here's an example:
http://develoq.net/2010/custom-controller-factory-in-asp-net-mvc/
As others have already stated you need to do one of the following:
Derive from IControllerFactory interface and provide an implementation of the CreateController and ReleaseController methods.
Derive from DefaultControllerFactory and override the default behaviours.
Here are some links to get you started:
Custom controller factory in ASP.Net
Inside the ASP.NET MVC Controller factory
Dive deep into MVC - IControllerFactory
Also, if you're willing to spend a bit of money I would also recommend the book Pro ASP.NET MVC 3 Framework as this explains almost every aspect of how the MVC framework can be customised (including an example on how to create a custom controller factory - the source code for which can be freely downloaded from the publishers website).
I think it is impossible to do this. ASP.NET MVC have defined the convention that we have to follow.
Controllers are in Controllers folder, views are in Views{ControllerName}\
I believe you cannot change the convention unless you create your own ControllerFactory.
If you really want to do that, just implement IControllerFactory interface (or try to derive from DefaultControllerFactory).
Then your Application_Start register your controller factory using ControllerBuilder.Current.SetControllerFactory method.
Look at the ControllerFactory documentation and to the MVC source code for details.
What you're asking and what your example shows are two different things; depending on which one you want to achieve, you may or may not need to do any work.
There are two requirements for a class to be a controller in the MVC Framework:
It has to have a class name of Name + "Controller"
It has to have a parameterless public constructor.
Your sample "normal" MVC layout is actually not valid:
MyMvcProject\Controllers\
MyController1.cs
MyController2.cs
MyController3.cs
Those classes wouldn't be found by MVC because they don't have the correct name, regardless of which folder they are in.
If all you want to do is change the namespace/folder names, that "just works", assuming you name them the same as the appropriate route segment(s):
MyMvcProject\MyGroup1\
Page1Controller.cs
Page2Controller.cs
MyMvcProject\MyGroup2\
Page3Controller.cs
MyMvcProject\Areas\Area1\
Area1Page1Controller.cs
This walkthrough (written for MVC 2 but works just as well in MVC3) shows you how to support Areas with the default controller behavior.
If you actually want to name them SomethingController1 or SomethingElseController5, or otherwise change the route -> classname mappings, then you do need to implement a custom ControllerFactory, and inject it into the MVC pipeline.
There are plenty of examples on the web on how to do this, including the one posted earlier.
I like ASP.Net MVC Authorize attribute, I can extend it and build my own logic and decorate my controller with it. BUT,
In my architecture, I have one common service layer(C# Class Library). End user can access my application via ASP.Net MVC web site or via my exposed REST WCF Webservice layer.
My asp.net MVC application and REST WCF service layer both in turn access my common service layer.
I want authorization to happen in this common service layer and not in ASP.Net MVC Controller or in my exposed REST Service layer.
Can I create ASP.Net MVC Authorize attribute like thing to decorate my methods in the common C# class library? This attribute will take parameters and will decide if the current user has access to perform that function or not?
Thanks & Regards,
Ajay
What you're looking for can be achieved using AOP library, like PostSharp (http://www.postsharp.org/). It's more complex than using Authorize attribute in mvc, but is still quite simple.
Another way to handle this is to use the [PrincipalPermission] attribute in your service layer. This can prevent callers from executing a method (or accessing an entire class) without the defined authorization.
No, AuthorizeAttribute works because the MVC framework explicitly invokes it before calling the method. A similar feature for your service layer would only work if your clients explicitly invoked it, as well. It would not be reasonable to presume that even a well-intentioned client would always remember to look for the attribute and invoke it. WCF has its own security. You should use that instead of writing your own.
This shouldn't be too hard to do - there are a couple of places that you could reflect out the attribute and handle it accordingly:
On application start in Global.asx you can customise routing and locations for views
Underlying ASP.Net request events still fire, so you could override one of them
Create your own base controller and override OnActionExecuting
Update following comment
Ahh, I see. In that case if you're making direct calls then you should check out Code Access Security, which I think covers what you mean.
Alternatively a custom attribute might make sense as long as you are using some kind of factory pattern - then the reflection call that gets the factory could check the attributes.
If you're not using reflection to retrieve your classes or call your methods (which is essentially what routing does in MVC) then you won't get the chance to check your attributes.