I have a Web API project where I intend on using an attribute that inherits from ActionFilterAttribute to do logging in a standardized fashion. As part of that logging, I want to extract some values from HttpActionContext in the OnActionExecuting method. I would then want to refer to these as part of OnActionExecuted. I have specified [AttributeUsage(AttributeTargets.Class)] for this attribute. My assumption is that my custom attribute would be instantiated in concert with the class it is applied to, and have the same lifetime as the class to which the attribute is applied. I can't find anything to concretely back this up. I've done some testing and that seems to be how it works but I worry that my test is too limited. I'm assuming that multiple calls to the same controller will generate new instances of that controller and thus new instances of the attribute. I'm basically worried about the thread safety of the data I retrieve as part of OnActionExcecuting.
Anyone know any resources or links that can confirm or deny my assumptions?
It depends on what you are going to use.
Attributes (filters) in Web API are cached (filter pipeline is private readonly Lazy<Collection<FilterInfo>> _filterPipeline; and initialized only once). see here
Therefore if you initialize something in the attribute's constructor, it will remain the same on subsequent executions.
However, the HttpActionContext is created created for every request from HttpControllerContext and HttpActionDescriptor and then passed on to each of the cached filters in the pipeline. see here
As a result, even though the instances of the filters are reused, the value of the context in the methods is specific to the specific request.
Related
Probably you can give me a hint about good practices: In order to learn a bit more about Web API, I'm trying to create a Web-Service which helps doing some work with the TFS.
It would be very cool, if the Client could select, which TFS he wants to use by passing kindahow an object, which contains the needed data since TFS Service URL etc. But this gives me some troubles:
I created a type called TFSConfiguation, to kindahow pass these information, but this has some drawbacks:
I can't use Get-Method,s since I'd need to pass this object via Body
Every method in every Controller needs to get this object passed
I (think I) can't use Dependency injection, since I need to pass this TFS-Parameter to the Layers behind the Controllers
Other approaches would all hurt the open closed principles I guess, since the Controller really doesn't know which concrete TFS is used.
Is there a good possibility to make such stuff work? If not, what would be the best case for such a scenario?
I can't use Get-Method,s since I'd need to pass this object via Body
The ModelBinder can bind from the URI.
Every method in every Controller needs to get this object passed
Or you let the user store it in the session with a call, and read it from the session in other calls.
I (think I) can't use Dependency injection, since I need to pass this TFS-Parameter to the Layers behind the Controllers
Why do you want to inject this?
You could create a POST endpoint that accepts a TfsConfiguration object and returns a token, such as a GUID, that is passed to GET endpoints via the URL or a custom header. The flow could be:
POST TfsConfiguraton to api/tfstoken, which returns the token
Routes which require the token have URLs of the form api/tfstoken/...
we have implemented a webAPI and we have a number of API controllers.
We provide an API documentation for our API and what we want to do is to exclude certain web methods from the documentation but we want this to be done dynamically depending on the environment we are running.
just to give you an understanding of what I mean, let's say I have the following web method
[ApiExplorerSettings(IgnoreApi = true)]
public Product getProduct()
{
...
}
By setting the IgnoreAPI property on the ApiExplorerSettingAttribute to true, it excludes the web method from the documentation which is what we want but we need a way of setting the "true" value dynamically.
Ideally we would like to have a database table with bool values for each webMethod and based on these set the value for IgnoreAPi property.
Is there a way to achieve this? Your help will be much appreciated.
You can implement a custom IApiExplorer and register it in Web API's services to have full control over which APIs are listed or not.
Here's a blog post from the dev who implemented most of this: https://learn.microsoft.com/en-us/archive/blogs/yaohuang1/asp-net-web-api-introducing-iapiexplorerapiexplorer
And here's the IApiExplorer interface definition: http://msdn.microsoft.com/en-us/library/system.web.http.description.iapiexplorer(v=vs.118).aspx
One thing you could do is derive from (or re-use the existing source of) the existing ApiExplorer implementation and call base to get the default list, and then further filter it however you want.
And per s_hewitt's comment, the recommendation is:
Deriving from ApiExplorer, implementing the two methods ShouldExploreAction and ShouldExploreController is the way to go. Make your DB calls in those two methods, looking up based on route, controller and action.
I don't know much about the documentation generation of WebAPI, but I do know about attributes. Attributes are compiled into the code and result in hard coded values being held in directly in the data in the EXE or DLL. They cannot be changed.
Having said that, you might be able to apply attributes as a second set after normal compilation. Perhaps PostSharp could help here? Perhaps changing the solution configuration could be a way of indicating the environment you want to build for and this which methods get the IgnoreApi treatment. You could create your own attribute to apply to the methods that describes which environments the method should be ignored within. (I think it's more likely you'll be able to do what you want in PostSharp if you don't try and call a database to get hold of this data.)
I have this situation where the fact that the user is not logged in is preventing the construction of my controller's dependencies.
[Authorize]
class MyController : Controller
{
public MyController(MyService service)
{
}
}
class MyService
{
public MyService()
{
// requires information which only
// becomes known after the user logs in
}
}
My question is: can I do something to cause the MVC framework to first look at the Authorize attribute and then resolve the controller instance?
The above would be much more preferable to me than either of the following:
Changing MyService to be able to handle being created before user log in
Injecting Func
Switching to service location
Ideally, I'd like to flip a switch in the MVC framework that says, "before you resolve the controller, check that you're actually going to use it and not toss it out due to lack of authorization and direct anyway..."
I have this situation where the fact that the user is not logged in is preventing the construction of my controller's dependencies.
That's the root of your problem.
// requires information which only becomes known after the user logs in
This means that the constructor of that service does too much. Constructors should not do more than store the incoming dependencies. This way you can compose object graphs with confidence.
The building of object graphs should in general be static. This means that the resolved object graph should not change based on runtime conditions (there are exceptions, but this is a good rule of thumb). It shouldn't matter whether or not a user is authorized or not, the service class should still be composed and injected. This means that authorization and loading of data is done at a later point in time; the moment that the request is actually executed (which is directly after the object graph is composed).
Your problem is that you don't really understand how the MVC Request pipeline works.
The first thing you have to realize is that Attributes are, in essence, designed to match up with identical events in the controller base class. There is an OnAuthorization method in Controller, and this is called either just before or just after the attributes OnAuthorization method is called.
So, in order for it to call both methods at roughly the same time, that means the Controller class must have been constructed to do so. What's more, a lot of other stuff goes on before Authorization filters, such as model binding, because your authorization filter may need information from the model to make its decision.
I suggest you check out this pipline chart.
https://www.simple-talk.com/dotnet/.net-framework/an-introduction-to-asp.net-mvc-extensibility/
I am working with a c# MVC website that has been developed over the course of several months by different people. The site is quite big and uses the .NET membership facilities regulate user access to various features.
I have now been tasked with a security audit, to list what users or roles have access to which features. I can do this by hand, but given the large number of controllers and their actions, it would be easier if I could do this with code. I am at a loss on how to even begin.
So, in short, how do I get a list of all the controllers on a site, their actions, and determine which, if any, users/roles have access to them?
You can use a little reflection to get controller methods. You can get your controllers:
var controllers = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(Controller));
where Controller is the standard base class; if you've got your own custom base controller you can use that instead. This assumes you're running this code within the app; if that's not the case then replace Assembly.GetExecutingAssembly() with the appropriate logic to find your app's assembly. Assembly.GetExecutingAssembly() is easier, so I'd say to just add a function to do this somewhere in your admin-only area, if there is such a thing.
That line above will give you an array of System.Type objects for your controllers. From there, foreach (var TController in controllers) through them and get their methods:
var actions = new ReflectedControllerDescriptor(typeof(TController)).GetCanonicalActions();
This gets you an array of ActionDescriptor objects, from which you can use GetFilterAttributes() and GetCustomAttributes() to see what attributes are on that method - you're mostly looking for AuthorizeAttribute, AllowAnonymousAttribute, and your custom auth stuff. The ReflectedControllerDescriptor has these methods as well, for attributes applied to the entire controller instead of per-method.
Once you know which auth-related attributes are set, you can inspect the properties of those methods to see what they're set to. For example, AuthorizeAttribute exposes a Roles property, so for a method marked [Authorise("admin", "superuser")] you'll get a string containing those terms, so with a little logic you can split it up into the individual role names and use those for grouping/sorting/whatever. For any custom attributes... well, that depends on how you've implemented them, but if they don't expose what you need you can always edit them so they do.
If your methods use something like User.IsInRole internally... well, I'm not sure there's a way to find that programmatically. You might be stuck using Call Hierarchy view or Find All References to see where that sort of method is being accessed, so you can sift through manually.
Meanwhile, as part of this audit it's probably worth logging what's actually being accessed, if you don't already. In my projects, I tend to implement an action filter inheriting from ActionFilterAttribute, using some logic that inspects the attributes as described above, and using the ActionDescriptor and HttpContext.User that get passed in as part of the filter context to record what action is being accessed and who's accessing it.
I have a RouteCollection and a string with an URL.
Has anybody an idea how can I get the name of the route that would be executed?
Some method like RouteCollection.PredictRoute(url) that will return the route name or the physical file that would be executed.
I want to create some statistics from web server log files. It would be very nice to reuse the used RouteCollection for that statistic.
Many thanks!
Here is a snippet of code I used to test that URLs were being mapped to their correct controller and action. You should be able to inspect the route name as well.
RouteConfig.RegisterRoutes(routes);
RouteData routeData = routes.GetRouteData(context);
string controller = routeData.Values["controller"];
string action = routeData.Values["action"];
The variable routes is a RouteCollection object and context is a HttpContextBase object.
I assume you want to do this outside of your MVC application, where requests and contexts are not available (only the log files, as you mentioned).
Unfortunately, that is not very easy to do. In order to write such a matching method you need to reuse (or worse, rewrite) the MVC framework code for URL parsing found in various classes in namespace System.Web.Http.Routing. The source code is available on CodePlex, under Apache 2.0 license.
Instead, I think there's an easier way you can include the route names in the log files and use them later in statistics. Have a look below.
What you could to do is extend the default MvcHandler class and override its ProcessRequest method. In there, you can call the base class implementation and right after it do your stuff by using RequestContext.RouteData.
The class RouteData contains, besides other things, also the current route (which you defined in your route collection. That is accessible through the RouteData.Route property.
This works because MvcHandler is always delegated (unless you've created your own MVC infrastructure) by the MvcRouteHandler, to handle the processing for each request. It is the one that gets the controller data from the existing route data, instantiates an IController implementation, and ultimately executes it.